Skip to content

feat: source-port-trust smell — the sender picks their own source port (v1.28.0) - #42

Merged
DannyRuizB merged 1 commit into
mainfrom
feat/source-port-trust
Aug 5, 2026
Merged

feat: source-port-trust smell — the sender picks their own source port (v1.28.0)#42
DannyRuizB merged 1 commit into
mainfrom
feat/source-port-trust

Conversation

@DannyRuizB

Copy link
Copy Markdown
Owner

Smell #37: source-port-trust

An inbound ACCEPT keyed on the source port (--sport 53, nft udp sport 53) with no destination port pinned. The source port is the cheapest field in the packet to forge — it is whatever socket the sender binds, and nmap -g/--source-port exists precisely to walk through rules like this — so "from port 53" admits anyone who remembers to set their source port, to every local port.

It is the pre-conntrack idiom for letting replies back in (DNS answers, active-FTP data); the modern spelling is ct state established,related accept.

Exemptions that keep it honest

  • dport pinned → spared: the service scopes the accept, sport is decoration, not the gate.
  • ESTABLISHED/RELATED-gated → spared: conntrack is the gate.
  • Not reachable from INPUT/FORWARD → not judged (BFS over jumps, the unused-chain machinery): on the OUTPUT side the sport is the host's own port and stateless egress rules legitimately match it (pinned by test).
  • DROP/REJECT by sport → unflagged: wide caution ok, borrowed trust not — the same rule as mac-based-trust and bogon-source-accept. This completes the spoofable-trust trilogy (MAC, bogon IP, source port).

Sample

The sloppy router earns the perfect backstory: its missing conntrack rule broke DNS, so the admin "fixed" it the pre-conntrack way — --sport 53 -j ACCEPT. missing-established-accept and this smell now fire as cause and effect.

Verificado en local

  • npm test: 165/165 (4 tests nuevos: fires/spares, dport+established exemptions, OUTPUT vs user-chain direction, nft spelling)
  • npm run lint: limpio

Linter: 36 → 37 smells.

🤖 Generated with Claude Code

…t (v1.28.0)

An inbound ACCEPT keyed on --sport (nft `udp sport`) with no destination
port pinned trusts the one packet field the sender types in for free:
nmap -g/--source-port exists precisely to walk through rules like this.
The pre-conntrack "let replies back in" idiom, flagged with three honest
exemptions: dport-pinned rules (the service is the gate), ESTABLISHED/
RELATED rules (conntrack is the gate), and anything not reachable from
INPUT/FORWARD (on the OUTPUT side the sport is the host's own port —
stateless egress rules legitimately match it; BFS over jumps decides).
Blocking by sport stays unflagged — wide caution ok, borrowed trust not.
Completes the spoofable-trust trilogy: MAC, bogon IP, source port.

The sloppy router gains the perfect backstory: its missing conntrack
rule broke DNS, so the admin "fixed" it with --sport 53 -j ACCEPT —
missing-established-accept and this smell now fire as cause and effect.

Linter goes from 36 to 37 smells. 165 tests (4 new).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@DannyRuizB
DannyRuizB merged commit f26d0a9 into main Aug 5, 2026
1 check passed
@DannyRuizB
DannyRuizB deleted the feat/source-port-trust branch August 5, 2026 12:24
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.

1 participant