Skip to content

fix(providers): read the SSRF Guard toggle from the dashboard, not only env - #14172

Merged
diegosouzapw merged 6 commits into
diegosouzapw:release/v3.8.51from
datrixlab:fix/ssrf-guard-flag-dashboard
Sep 29, 2026
Merged

diegosouzapw merged 6 commits into
diegosouzapw:release/v3.8.51from
datrixlab:fix/ssrf-guard-flag-dashboard

Conversation

@datrixlab

Copy link
Copy Markdown
Contributor

Summary

  • "SSRF Guard" (OUTBOUND_SSRF_GUARD_ENABLED) is a toggle on the Feature Flags page, with requiresRestart: false. Its only reader is the legacy escape hatch in arePrivateProviderUrlsAllowed() (src/shared/network/outboundUrlGuardPolicy.ts), and that reads process.env only. The toggle writes a DB override, which nothing reads.
  • The two directions:
env OUTBOUND_SSRF_GUARD_ENABLED dashboard toggle page shows guard mode, before after
unset OFF off, source db block-metadata none
false ON on, source db none block-metadata
false not set off, source env none none
unset not set on, source default block-metadata block-metadata

The second row is the one that matters. The page reports the guard as on, while provider validation, outbound fetches (getProviderOutboundGuard) and webhooks run with no private-host checks. feature-flags/route.ts has special cases so that "the dashboard never shows a source that doesn't match actual gate behavior"; this flag has none, so it should follow the generic DB-then-env order.

  • Fix: read the DB override first and fall back to env when it is unset or empty. This is the same shape step 1 of the same function uses for OMNIROUTE_ALLOW_PRIVATE_PROVIDER_URLS, and the same order as resolveFeatureFlag(). With no DB override the result is identical to before for every env value.

Related Issues

Validation

  • Change type: security / provider URL guard
  • Focused tests: the new file plus outbound-url-guard-feature-flag, outbound-url-guard-local-flag, rerank-remote-provider-nodes (28/28)
  • Wide run: every unit test file that mentions the outbound guard, feature flags or webhooks (78 files). All pass except feature-flags-doc-sync-static and telegram-keycache-bounded-13165, which fail the same way on a clean release/v3.8.51 on Windows.
  • tsc on the changed files (temp tsconfig extending the root one): clean; eslint clean; prettier --check clean
  • Based on the current release/v3.8.51
  • Production-code change includes a new automated test

Tests Added Or Updated

  • tests/unit/outbound-url-guard-ssrf-flag.test.ts (new). Each case clears and restores this flag and both sibling flags, env and DB:
    • a DB ON beats OUTBOUND_SSRF_GUARD_ENABLED=false in env (validation and outbound guards back to block-metadata);
    • a DB OFF opens private URLs with no env var set;
    • the webhook check follows the DB toggle (a 192.168.x webhook is rejected again);
    • an empty DB value leaves env false in effect;
    • env false with no DB override still opens private URLs, as before;
    • nothing set: private URLs stay closed.

With outboundUrlGuardPolicy.ts reverted, the first three fail and the other three pass.

Coverage Notes

  • The changed branch is exercised with the DB override set, unset and empty, and with env set and unset.

Reviewer Notes

  • Upgrade effect: a DB override that used to do nothing starts to work. Someone who once switched the SSRF Guard off in the dashboard, with no env var, moves from block-metadata to none on upgrade, the same state the env escape hatch already gives. The flag is warningLevel: "info" while "Allow Private Provider URLs" is "caution", and both now reach none. I left the level alone to keep this to the precedence; raising it to "caution" is a one-line change if you want it here.
  • The changelog fragment notes the upgrade effect.

…ly env

arePrivateProviderUrlsAllowed() read OUTBOUND_SSRF_GUARD_ENABLED from
process.env only, while the Feature Flags page shows and writes it as a
DB override. Switching the guard off in the dashboard did nothing, and
switching it on did not undo OUTBOUND_SSRF_GUARD_ENABLED=false in env:
the page showed the guard on with source db while provider validation,
outbound fetches and webhooks ran with no private-host checks.

Read the DB override first and fall back to env when it is unset or
empty, the same way step 1 of the function reads the private-URL flag.
# Conflicts:
#	src/shared/network/outboundUrlGuardPolicy.ts
…ests

The DB overrides open the SQLite handle; without resetDbInstance() in
test.after the runner never exits on its own.
@diegosouzapw
diegosouzapw merged commit fa7d936 into diegosouzapw:release/v3.8.51 Sep 29, 2026
11 of 16 checks passed
woodsonl added a commit to woodsonl/OmniRoute that referenced this pull request Oct 6, 2026
The v3.8.52 merge changed the code the corrected notes describe. Re-checked
every claim by code area and fixed what no longer held:

- OUTBOUND_SSRF_GUARD_ENABLED is no longer read from the environment only:
  its dashboard toggle (DB override) is read first (upstream diegosouzapw#14172).
- Guard blocks surface as 503 (400 on model discovery), not 422, and are
  audited as provider.validation.ssrf_blocked events, not providerAudit.ts.
- In public-only mode the safe-fetch wrapper also resolves the hostname and
  refuses private answers; the as-written check still runs first.
- .env.selfhost.example: an empty INITIAL_PASSWORD behaves like unset.
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