Summary
The public redirect service records attacker-controlled values as unbounded Prometheus label sets, allowing an unauthenticated memory-exhaustion DoS, and exposes PII (client IPs, user agents, per-slug traffic) on an unauthenticated /metrics endpoint. IP attribution in the metrics is also spoofable via X-Forwarded-For.
Evidence
crates/vym-fyi-server-redirect/src/handlers/short_link.rs:23-28 — redirect_slug_requests_total uses the raw slug as a label ("slug" => slug.clone()). The adjacent slug_len bucketing (line 22 comment) only bounds slug_len, not the full slug label. Note this counter is incremented for every request, including non-existent slugs.
crates/vym-fyi-model/src/services/axum_metrics.rs:53-60 — http_requests_by_ip_total labels include path (= the slug on the redirect server), user_agent, and client_ip.
crates/vym-fyi-model/src/services/axum_metrics.rs:99-110 — extract_ip trusts the first X-Forwarded-For value unconditionally; there is no trusted-proxy configuration.
/metrics is registered with no auth on both servers (crates/vym-fyi-server-redirect/src/main.rs:41-43, crates/vym-fyi-server-crud/src/main.rs:46-49).
- The
metrics crate recorder (via axum-prometheus) stores every unique name+label-set in memory and never evicts.
Exploitation scenarios
- Memory-exhaustion DoS (public, unauthenticated): attacker issues
GET /<random> with a unique User-Agent and unique spoofed X-Forwarded-For per request → millions of in-memory time series → OOM / restart loop.
- PII disclosure: anyone reaching
/metrics reads every client IP, user agent, and per-slug hit counts (link-usage disclosure).
- Spoofing/framing: attacker sets
X-Forwarded-For: <victim-ip> → victim's IP is attributed to attacker traffic in dashboards/alerts.
Severity: HIGH.
Suggested fix
- Drop the
slug label from redirect_slug_requests_total (keep only slug_len).
- In
record_ip_metrics: bucket/truncate path; truncate or hash user_agent; never store raw client_ip as a label (or bound it via a fixed-size hash).
- Trust
X-Forwarded-For only when the peer is a configured trusted proxy (fall back to the socket address).
- Require auth (or network-scoped access) for
/metrics.
Summary
The public redirect service records attacker-controlled values as unbounded Prometheus label sets, allowing an unauthenticated memory-exhaustion DoS, and exposes PII (client IPs, user agents, per-slug traffic) on an unauthenticated
/metricsendpoint. IP attribution in the metrics is also spoofable viaX-Forwarded-For.Evidence
crates/vym-fyi-server-redirect/src/handlers/short_link.rs:23-28—redirect_slug_requests_totaluses the raw slug as a label ("slug" => slug.clone()). The adjacentslug_lenbucketing (line 22 comment) only boundsslug_len, not the fullsluglabel. Note this counter is incremented for every request, including non-existent slugs.crates/vym-fyi-model/src/services/axum_metrics.rs:53-60—http_requests_by_ip_totallabels includepath(= the slug on the redirect server),user_agent, andclient_ip.crates/vym-fyi-model/src/services/axum_metrics.rs:99-110—extract_iptrusts the firstX-Forwarded-Forvalue unconditionally; there is no trusted-proxy configuration./metricsis registered with no auth on both servers (crates/vym-fyi-server-redirect/src/main.rs:41-43,crates/vym-fyi-server-crud/src/main.rs:46-49).metricscrate recorder (viaaxum-prometheus) stores every unique name+label-set in memory and never evicts.Exploitation scenarios
GET /<random>with a uniqueUser-Agentand unique spoofedX-Forwarded-Forper request → millions of in-memory time series → OOM / restart loop./metricsreads every client IP, user agent, and per-slug hit counts (link-usage disclosure).X-Forwarded-For: <victim-ip>→ victim's IP is attributed to attacker traffic in dashboards/alerts.Severity: HIGH.
Suggested fix
sluglabel fromredirect_slug_requests_total(keep onlyslug_len).record_ip_metrics: bucket/truncatepath; truncate or hashuser_agent; never store rawclient_ipas a label (or bound it via a fixed-size hash).X-Forwarded-Foronly when the peer is a configured trusted proxy (fall back to the socket address)./metrics.