Skip to content

fix(gateway): validate MEDIA tag paths to block arbitrary local file … - #6084

Closed
Ruzzgar wants to merge 1 commit into
NousResearch:mainfrom
Ruzzgar:fix/gateway-media-tag-file-exfiltration
Closed

fix(gateway): validate MEDIA tag paths to block arbitrary local file …#6084
Ruzzgar wants to merge 1 commit into
NousResearch:mainfrom
Ruzzgar:fix/gateway-media-tag-file-exfiltration

Conversation

@Ruzzgar

@Ruzzgar Ruzzgar commented Apr 8, 2026

Copy link
Copy Markdown
Contributor

Context

MEDIA: directives are intended for explicit media attachment delivery (images/audio/video), but the parser currently accepts overly broad path tokens.
This creates a trust-boundary issue: model-generated text can influence which local files are sent as platform attachments.

What’s wrong (concrete exploit path)

A crafted response such as:

  • MEDIA:'/etc/passwd'
  • MEDIA:/tmp/secrets.env
  • MEDIA:"/home/user/.ssh/config"

can be parsed as a valid attachment candidate and routed into native send flows (send_document / send_image_file / send_video), depending on adapter behavior.

That means non-media host files can be exfiltrated through normal chat output delivery.

Behavioral change in this PR

MEDIA: extraction is now strict and intentionally conservative:

Rule Before After
Remote schemes (http://, https://, etc.) Could pass parser path branch in edge cases Rejected
Relative paths Could be accepted depending on token shape Rejected
Absolute local paths Accepted Accepted only if extension is allowlisted media type
Non-media extensions (.env, .txt, .conf, etc.) Could be extracted Rejected

Implementation overview

gateway/platforms/base.py

  • Added _normalize_media_tag_path() as a single validation gate for MEDIA: values.
  • Added media extension allowlist for extracted attachment paths.
  • Added explicit remote-scheme and path-shape checks (local absolute paths only).
  • Updated extract_media() to use normalized/validated output only.

Regression coverage

tests/gateway/test_platform_base.py

Added:

  • test_media_tag_ignores_non_media_file_paths

This test verifies that sensitive/non-media files are not extracted from MEDIA: tags and therefore are not eligible for attachment routing.

Why this fix is scoped correctly

  • No adapter-specific refactor.
  • No protocol/UX changes for valid media paths.
  • No new dependencies.
  • Keeps existing MEDIA: contract for real media outputs intact.

Validation status

  • Regression test added
  • No new dependencies

@alt-glitch alt-glitch added type/security Security vulnerability or hardening P1 High — major feature broken, no workaround comp/gateway Gateway runner, session dispatch, delivery labels Apr 30, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

Likely duplicate of #16547 — same MEDIA: path traversal vulnerability. Also overlaps with #10026. All three restrict MEDIA paths to prevent local file exfiltration.

1 similar comment
@alt-glitch

Copy link
Copy Markdown
Collaborator

Likely duplicate of #16547 — same MEDIA: path traversal vulnerability. Also overlaps with #10026. All three restrict MEDIA paths to prevent local file exfiltration.

@egilewski

Copy link
Copy Markdown
Contributor

merge conflicts

This PR does not merge cleanly with the base branch. Please rebase or merge current main and resolve the conflicts if it's still relevant.

Signed: GPT-5.5-low in Codex

@teknium1

Copy link
Copy Markdown
Contributor

Thanks for the security-minded report, @Ruzzgar — and for the tests. After verifying against current main, I'm closing this as already-covered.

The vulnerability doesn't exist on current main. extract_media() only parses MEDIA: tags out of the response text. The actual security boundary lives one layer down at delivery: every extracted path is run through validate_media_delivery_path() (gateway/platforms/base.py) via filter_media_delivery_paths() before any attachment is sent (gateway/run.py). That guard already blocks /etc, /proc, /sys, /dev, /root, ~/.ssh, ~/.aws, ~/.hermes/.env, auth.json, etc., with a recency window and an opt-in strict mode for public-facing gateways (HERMES_MEDIA_DELIVERY_STRICT=1).

Verified live:

extract_media("MEDIA:/etc/passwd")  -> [('/etc/passwd', False)]   # parsed
filter_media_delivery_paths(...)     -> []                         # dropped at delivery
# log: "Skipping unsafe MEDIA directive path: /etc/passwd"

This permissive-by-default, validate-at-delivery design is intentional (#29523) — it's symmetric with inbound delivery (platforms hand the agent any uploaded file, the agent can hand back any non-credential file), with strict mode for the public-bot threat model.

Two reasons not to land the change as written:

  1. It duplicates an existing guard at the wrong layer (extraction vs delivery).
  2. Its hardcoded media-extension allowlist would regress legitimate deliverables that delivery currently allows — .md, .pdf, .docx, .txt, etc. (those flow through validate_media_delivery_path, not an ext gate). The added test asserting MEDIA:'/etc/passwd' stays as literal text also reverts the intended extract-then-validate behavior.

Closing as superseded by the existing delivery-path validation. Appreciate the contribution — if you hit a path that actually does slip through validate_media_delivery_path, that'd be a real bug and very welcome.

@teknium1 teknium1 closed this Jun 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/gateway Gateway runner, session dispatch, delivery P1 High — major feature broken, no workaround type/security Security vulnerability or hardening

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants