# REPRO-2026-00285: Samba’s printing subsystem allows OS command injection via unescaped job description (%J), enabling remote code execution through crafted print jobs. ## Summary Status: published Severity: high Type: security Confidence: high ## Identifiers REPRO ID: REPRO-2026-00285 CVE: CVE-2026-4480 ## Package Name: samba-team/samba Ecosystem: generic Affected: All Samba versions before the fix (advisory says 'All versions') Fixed: Unknown ## Root Cause # Root Cause Analysis: CVE-2026-4480 — Samba Printing Subsystem OS Command Injection via %J ## Summary CVE-2026-4480 is an unauthenticated remote code execution vulnerability in Samba's printing subsystem. When a Samba server is configured with a non-CUPS/non-iPrint printing backend (e.g., `printing = sysv`) and a `print command` that includes the `%J` substitution character (job description), a remote attacker can submit a print job whose document name contains shell metacharacters. Samba substitutes the client-controlled job name into the `print command` string and executes it via `system()` with only partial sanitization — the characters `$ \` " ' ; %` are stripped, but `& ( ) # | < >` and others survive, enabling OS command injection and arbitrary code execution as the Samba service account. ## Impact - **Package/component affected:** Samba `smbd` printing subsystem — `source3/printing/print_generic.c`, function `generic_job_submit()` → `print_run_command()` → `smbrun_no_sanitize()` → `system()` - **Affected versions:** All Samba versions prior to 4.22.10, 4.23.8, and 4.24.3 (released 26 May 2026). Verified vulnerable on 4.22.9. - **Risk level:** Critical (CVSS 3.1 base 10.0 — AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H). Unauthenticated, remote, default guest print access. - **Consequences:** Arbitrary OS command execution with the privileges of the Samba service (typically `nobody` or the configured `guest account`). Full server compromise possible. ## Impact Parity - **Disclosed/claimed maximum impact:** Remote code execution (unauthenticated, network-reachable) - **Reproduced impact from this run:** Remote code execution confirmed — the `id` command executed on the Samba server and its output (`uid=65534(nobody) gid=65534(nogroup) groups=65534(nogroup)`) was captured in the server-side log, plus an arbitrary file (`marker`) was created in the spool directory by the injected `touch` command. All via an unauthenticated guest SMB connection over TCP 445. - **Parity:** `full` - **Not demonstrated:** A full reverse shell or privilege escalation to root was not demonstrated (the Samba guest account runs as `nobody`), but the core claim of unauthenticated remote code execution is fully reproduced. ## Root Cause ### Vulnerable code path When a client opens a file on a printable SMB share, `smbd` processes it as a print job: 1. `smbd/open.c` → `print_spool_open(fsp, filename, vuid)` — the client-supplied filename becomes the document name (`docname = "Remote Downlevel Document "`) 2. `print_spool_open()` → `print_job_start(docname)` → `fstrcpy(pjob.jobname, docname)` — the docname is stored as the job name with **no sanitization** 3. On file close → `print_job_end()` → `generic_job_submit()` 4. `generic_job_submit()` in `source3/printing/print_generic.c`: ```c jobname = talloc_strdup(ctx, pjob->jobname); jobname = talloc_string_sub(ctx, jobname, "'", "_"); // only replaces ' → _ ... ret = print_run_command(snum, ..., lp_print_command(snum), NULL, "%s", p, "%J", jobname, ...); ``` 5. `print_run_command()` substitutes `%J` with the jobname using `talloc_string_sub()`: ```c syscmd = talloc_string_sub(ctx, syscmd, arg, value); // arg="%J", value=jobname ``` 6. `talloc_string_sub()` calls `talloc_string_sub2()` with `remove_unsafe_characters=true`, which replaces only `$ \` " ' ; % \r \n` with `_` in the **insert** (jobname) string 7. The resulting command string is passed to `smbrun_no_sanitize()` → `execl("/bin/sh", "sh", "-c", cmd, NULL)` — **no shell escaping** ### The gap The `talloc_string_sub2()` unsafe-character list is: ```c case '$': case '`': case '"': case '\'': case ';': case '%': case '\r': case '\n': ``` This misses critical shell metacharacters: `&`, `|`, `<`, `>`, `(`, `)`, `#`, space, `!`, etc. The `&` character (and `&&`) is a valid command separator in POSIX shells and is **not** in the sanitized set. An attacker can inject `&&` in the job description to chain arbitrary commands. ### The fix (commit `b80131fcf582`) The fix in Samba 4.22.10 adds `replace_print_cmd_J()` which: - Defines `STRING_SUB_UNSAFE_CHARACTERS "$\`\"';%|&<>"` (includes `&`, `|`, `<`, `>`) - Masks ALL unsafe characters (plus `/` and `\`) to `_` - Wraps the `%J` substitution in single quotes (or falls back to a fixed `__CVE-2026-4480_FallbackJobname__` string for mixed-quoting configurations) - Pre-substitutes `%J` in the print command before passing to `print_run_command`, removing the raw `%J` → jobname path Fix commit: `b80131fcf582ecc8e8c1b97e6051bb324bb8bef8` (Samba master), backported to 4.22.10, 4.23.8, 4.24.3. ## Reproduction Steps 1. **Reference:** `bundle/repro/reproduction_steps.sh` 2. **What the script does:** - Builds vulnerable Samba 4.22.9 and fixed Samba 4.22.10 from source (or reuses cached builds from the project cache) - Configures `smbd` with `printing = sysv`, a `printcap` entry for printer `testprn`, and a `print command` referencing unquoted `%J`: `(echo %J) > /tmp/samba_printlog 2>&1` - Starts the real `smbd` daemon listening on TCP port 445 with guest-accessible printing - Uses an impacket-based Python SMB client to connect over TCP 445 (guest/anonymous login), open a file named `PWN&&id&&touch marker&&END` on the `[testprn]` printable share, write print data, and close it - The server substitutes the document name (becomes `%J`) into the print command and executes it via `system()` — the `&&` survives sanitization, causing `id` and `touch marker` to execute - Repeats the same exploit against the fixed Samba 4.22.10 as a negative control 3. **Expected evidence of reproduction:** - **Vulnerable (4.22.9):** `/tmp/samba_printlog` contains `uid=65534(nobody)...` (output of injected `id` command) and a `marker` file is created in the spool directory - **Fixed (4.22.10):** `/tmp/samba_printlog` contains the literal masked string `PWN__id__touch marker__END` (no `uid=`, no command execution) and no `marker` file is created ## Evidence ### Vulnerable Samba 4.22.9 — RCE confirmed **Print log** (`bundle/artifacts/smb-vuln/printlog.txt`): ``` Remote Downlevel Document PWN uid=65534(nobody) gid=65534(nogroup) groups=65534(nogroup) sh: 1: END: not found ``` The `uid=65534(nobody)` line is the output of the injected `id` command — **arbitrary code execution proven**. **Marker file** (`bundle/artifacts/smb-vuln/marker_check.txt`): ``` -rw-rw-rw- 1 nobody nogroup 0 Jul 12 21:47 /tmp/sambatest/spool/marker ``` Created by the injected `touch marker` command running as `nobody` (the Samba guest account). **smbd log** (`bundle/artifacts/smb-vuln/smbd_command_log.txt`): ``` Running the command `(echo Remote Downlevel Document PWN&&id&&touch marker&&END) > /tmp/samba_printlog 2>&1' gave 127 ``` The `&&` is intact in the executed command — no shell escaping applied. ### Fixed Samba 4.22.10 — injection blocked (negative control) **Print log** (`bundle/artifacts/smb-fixed/printlog.txt`): ``` Remote Downlevel Document PWN__id__touch marker__END ``` The `&&` was masked to `__` and the jobname was wrapped in single quotes — **no command execution**. **Marker file** (`bundle/artifacts/smb-fixed/marker_check.txt`): ``` no marker (correct) ``` **smbd log** (`bundle/artifacts/smb-fixed/smbd_command_log.txt`): ``` Running the command `(echo 'Remote Downlevel Document PWN__id__touch marker__END') > /tmp/samba_printlog_fixed 2>&1' gave 0 ``` The jobname is single-quoted and masked — safe execution. ### Environment - Samba built from source: `samba-4.22.9` (vulnerable, commit `ff3dd69`) and `samba-4.22.10` (fixed, commit `0abface`) - Build: `--bundled-libraries=ALL --without-ad-dc --disable-python` (standalone file/print server) - OS: Ubuntu 26.04 LTS, 32 cores - Client: impacket 0.13.1 SMBConnection over TCP 445, guest/anonymous authentication ## Recommendations / Next Steps 1. **Upgrade immediately** to Samba 4.22.10, 4.23.8, or 4.24.3 (or later) 2. **Remove `%J`** from `print command` in `smb.conf`, or wrap it in single quotes (`'%J'`) as a temporary mitigation 3. **Switch to CUPS** (`printing = cups`) — CUPS/iPrint backends bypass the vulnerable `generic_job_submit()` path 4. **Disable guest printer access** — require authentication for print shares 5. **Audit** existing Samba deployments for `print command` entries containing `%J` ## Additional Notes - **Idempotency:** The reproduction script cleans all state directories between runs and re-creates them fresh. Each vulnerable/fixed test uses a separate base directory. - **SMB filename restrictions:** The classic SMB print path restricts the filename (and thus the jobname) to characters valid in SMB/CIFS names (no `/ \ : * ? " < > |`). The `&` character is allowed in SMB filenames and is not sanitized by the vulnerable `talloc_string_sub()`, making it the key injection vector. The spoolss RPC path (`StartDocPrinter` with `pDocName`) is not subject to SMB filename restrictions and allows even more characters, but the same `&` injection works through both paths. - **Why `&&` and not `;` or `$()`:** The vulnerable `talloc_string_sub2()` sanitizes `;`, `$`, and backtick but NOT `&`. The `&&` operator is a valid POSIX shell command separator that passes through the sanitization, enabling command chaining. - **The `echo %J >> file` vs `(echo %J) > file 2>&1` difference:** The subshell in the print command captures all output (including the injected commands' stdout/stderr) in the log file, providing clear RCE evidence. ## Reproduction Details Reproduced: 2026-07-13T05:29:04.742Z Duration: 1735 seconds Tool calls: 343 Turns: Unknown Handoffs: 2 ## Quick Verification Run one of these commands to verify locally: pruva-verify REPRO-2026-00285 pruva-verify CVE-2026-4480 Or open in GitHub Codespaces (zero-friction, auto-runs): https://github.com/codespaces/new?ref=repro/REPRO-2026-00285&repo=N3mes1s/pruva-sandbox Or download and run the script manually: curl -O https://api.pruva.dev/v1/reproductions/REPRO-2026-00285/artifacts/bundle/repro/reproduction_steps.sh chmod +x reproduction_steps.sh ./reproduction_steps.sh WARNING: Run in a sandboxed environment. This exploits a real vulnerability. ## References - NVD: https://nvd.nist.gov/vuln/detail/CVE-2026-4480 - Source: https://nvd.nist.gov/vuln/detail/CVE-2026-4480 ## Artifacts - bundle/repro/reproduction_steps.sh (reproduction_script, 11809 bytes) - bundle/repro/rca_report.md (analysis, 9569 bytes) - bundle/vuln_variant/reproduction_steps.sh (reproduction_script, 11729 bytes) - bundle/vuln_variant/rca_report.md (analysis, 14345 bytes) - bundle/artifact_promotion_manifest.json (other, 13898 bytes) - bundle/artifact_promotion_report.json (other, 13916 bytes) - bundle/vuln_variant/source_identity.json (other, 729 bytes) - bundle/vuln_variant/root_cause_equivalence.json (other, 2792 bytes) - bundle/logs/CVE-2026-4480_fix.patch (other, 5869 bytes) - bundle/repro/validation_verdict.json (other, 962 bytes) - bundle/repro/runtime_manifest.json (other, 1065 bytes) - bundle/logs/reproduction_steps.log (log, 3244 bytes) - bundle/logs/vuln_variant/variant_repro.log (log, 3482 bytes) - bundle/vuln_variant/spoolss_exploit.py (script, 7097 bytes) - bundle/vuln_variant/variant_manifest.json (other, 3892 bytes) - bundle/vuln_variant/validation_verdict.json (other, 3164 bytes) - bundle/vuln_variant/patch_analysis.md (documentation, 6596 bytes) - bundle/vuln_variant/runtime_manifest.json (other, 1576 bytes) ## API Access - JSON: https://api.pruva.dev/v1/reproductions/REPRO-2026-00285 - Script: https://api.pruva.dev/v1/reproductions/REPRO-2026-00285/artifacts/bundle/repro/reproduction_steps.sh - Web: https://pruva.dev/r/REPRO-2026-00285 ## For AI Assistants To help users with this reproduction: 1. The `pruva-verify` command is the simplest way to run the reproduction 2. The script downloads and runs automatically in an isolated temp directory 3. Always recommend running in a VM, container, or disposable environment 4. The root cause explains the technical vulnerability --- Generated by Pruva | https://pruva.dev