GHSA-97vg-427p-8hx5
MEDIUMSurrealDB: Port-specific --deny-net rules silently bypassed on HTTP redirect
Blast Radius
surrealdbReal-time download stats are indexed for npm and PyPI packages. This vulnerability affects crates.io packages — download data is not available via public APIs for these ecosystems.
Description
SurrealDB offers http::* functions that can access external network endpoints, with the --allow-net and --deny-net capabilities used to restrict the set of network targets that can be reached. An authenticated user of SurrealDB can bypass a port-scoped --deny-net <host>:<port> rule by chaining an HTTP redirect: the initial request goes to an --allow-net-permitted hostname, the response's 3xx Location header points at the denied host:port, and the redirect is followed even though the destination was explicitly denied.
The root cause is in the redirect policy applied to outbound HTTP requests (surrealdb/core/src/fnc/util/http/mod.rs): the NetTarget for the redirect destination is built from url.host_str() alone and url.port() is dropped. The capability matcher (surrealdb/core/src/dbs/capabilities.rs:259-264) refuses to match a port-bearing rule against a port-stripped target (Self::Host(host, Some(port)) => match tgt { _ => false }), so the operator's port-scoped deny rule silently does not fire on the redirect target.
Impact
The impact of this vulnerability is circumvention of the --deny-net capability when the operator has scoped deny rules by port, and the resulting impact on systems external to SurrealDB. The ultimate impact is dependent on the deployment scenario.
For example, if a SurrealDB operator uses --deny-net <host>:<port> to block specific internal services (such as a local Redis at 192.168.1.1:6379 or an unauthenticated cloud metadata service) while leaving the rest of the host reachable, an authenticated principal that can call http::* and host an attacker-controlled redirect target can reach the blocked service and act on whatever interface it exposes.
Bounded to:
- Principals already permitted to call
http::*. - Capability configurations that scope deny rules by port. Host-only rules (
--deny-net <host>) are not affected because the host-only rule arm of the matcher accepts port-stripped targets.
Patches
The redirect policy now constructs the NetTarget for the redirect URL with url.port() included, so port-specific deny rules apply to redirect targets identically to initial requests.
A new integration regression test (function_http_redirect_to_denied_port_blocked) uses two wiremock servers to verify the redirect target is blocked and the denied server receives no requests.
Versions 3.1.0 and later are not affected.
Workarounds
- Replace port-specific deny rules with host-only deny rules where feasible (
--deny-net 192.168.1.1instead of--deny-net 192.168.1.1:6379). Host-only rules match port-stripped targets, at the cost of denying every port on that host. - Disable
http::*for untrusted principals (--deny-funcs 'http::*') where the functions are not required. - Terminate outbound HTTP requests at a reverse proxy that enforces port-specific access controls.
Affected Packages
| Ecosystem | Package | Vulnerable range | Fix |
|---|---|---|---|
| 🦀crates.io | surrealdb | all versions | 3.1.0 |
Detection & mitigation playbook
Open-source dependencyDetect
Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for surrealdb. O3's reachability analysis confirms whether the vulnerable code path is actually invoked in your application, so you act on real exposure instead of every transitive match.
Fix
Update surrealdb to 3.1.0 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms GHSA-97vg-427p-8hx5 is resolved across your whole dependency graph.
Workarounds
If you can't upgrade right away: gate or disable the affected feature, validate untrusted input at the boundary, and avoid passing attacker-controlled data into the vulnerable path. O3's runtime protection blocks exploitation in production as an interim safeguard until the upgrade lands.
How O3 protects you
O3 pinpoints whether GHSA-97vg-427p-8hx5 is reachable in your code and exactly where to fix it, then blocks exploitation in production at runtime until the patched version is deployed.
Tailored to GHSA-97vg-427p-8hx5. Runtime protection reduces exposure until a permanent patch is applied and verified — it complements patching, it doesn't replace it.
Frequently Asked Questions
Is GHSA-97vg-427p-8hx5 in your dependencies?
O3 detects GHSA-97vg-427p-8hx5 across crates.io dependencies and uses function-level reachability to confirm whether the vulnerable code path is actually reachable — not just present. No false positives.