Skip to content

fix(net): reject control-char / path-traversal injection in wireguard/ipsec/migrate config fields (1.1.21)#224

Merged
click0 merged 1 commit into
mainfrom
claude/analyze-test-coverage-nCOJW
Jul 7, 2026
Merged

fix(net): reject control-char / path-traversal injection in wireguard/ipsec/migrate config fields (1.1.21)#224
click0 merged 1 commit into
mainfrom
claude/analyze-test-coverage-nCOJW

Conversation

@click0

@click0 click0 commented Jul 7, 2026

Copy link
Copy Markdown
Owner

Summary

The pure-module audit found three sinks where a less-trusted string was emitted verbatim into a generated config or used as a filesystem path without a control-character / traversal check. Each is fixed with validation in the pure (unit-tested) layer.

WireGuard — lib/wireguard_pure.cpp

validateConfig validated keys, CIDRs, ports and endpoints, but never the free-text FwMark, DNS, MTU, and peer description fields — all written straight into the wg-quick .conf. An embedded newline escapes the line and injects its own directive, most dangerously PostUp = <cmd>, which wg-quick runs as root. New hasControlChar helper rejects any byte < 0x20 or == 0x7f (incl. \n/\r) in those fields.

IPsec — lib/ipsec_pure.cpp

validateConfig never checked leftid / rightid / description, all emitted into ipsec.conf (leftid=… / rightid=… / # …). A newline injects an arbitrary conn option, e.g. rightsubnet=0.0.0.0/0, silently widening the tunnel policy. Control bytes in those three fields are now rejected.

migrate — lib/migrate_pure.{h,cpp} + lib/migrate.cpp

New validateArtifactFile. The artifact filename comes from the source server's /export JSON (extractFileField) and is concatenated into workDir + "/" + name, then used as both a curl -o target and an unlink() target. A hostile/compromised source returning "../../../etc/cron.d/pwn" got arbitrary file write and delete on the migrating host. The filename is now validated as a single safe path component (no /, no .., no control bytes, ≤ 255 chars) in lib/migrate.cpp before use.

Tests

New wireguard_pure_test, ipsec_pure_test, and migrate_pure_test cases cover each rejection (newline / traversal / slash / control byte) and confirm clean values still validate. All three suites pass locally.

Version

Bumps to 1.1.21; CHANGELOG.md entry and docs/trust-model.{md,uk.md} Applies-to line updated.

🤖 Generated with Claude Code


Generated by Claude Code

…/ipsec/migrate config fields (1.1.21)

Three sinks emitted a less-trusted string verbatim into a generated
config or used it as a filesystem path without a control-char /
traversal check:

- WireguardPure::validateConfig never checked the free-text FwMark,
  DNS, MTU, and peer description fields, all written into the wg-quick
  .conf. An embedded newline injects a directive — most dangerously
  `PostUp = <cmd>`, which wg-quick runs as root. New hasControlChar
  helper rejects any byte < 0x20 or == 0x7f in those fields.

- IpsecPure::validateConfig never checked leftid/rightid/description,
  emitted into ipsec.conf. A newline injects an arbitrary conn option
  (e.g. rightsubnet=0.0.0.0/0, silently widening tunnel policy).

- MigratePure gained validateArtifactFile: the artifact filename comes
  from the source server's /export JSON and is used as both a `curl -o`
  and an `unlink()` path. A hostile source returning
  "../../../etc/cron.d/pwn" got arbitrary file write + delete. It is
  now validated as a single safe path component before use in
  lib/migrate.cpp.

Adds wireguard/ipsec/migrate pure-test cases for each rejection and a
clean-value accept. Bumps version to 1.1.21; CHANGELOG + trust-model
(en/uk) updated.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01X6t6tzVypHye5bDGLxzmZK
@click0 click0 merged commit 2349d2f into main Jul 7, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants