Skip to content

Add format and length validation to ingest ipAddress to mitigate SSRF - #377

Merged
birme merged 1 commit into
mainfrom
security-audit/250-ingest-ipaddress-validation
Sep 28, 2026
Merged

birme merged 1 commit into
mainfrom
security-audit/250-ingest-ipaddress-validation

Conversation

@birme

@birme birme commented Sep 28, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Add a strict IPv4/IPv6 pattern (plus the existing maxLength: 128) to the ipAddress field of the NewIngest TypeBox model in src/models.ts, so malformed values are rejected at the schema boundary with a 400.
  • This closes an SSRF / request-injection gap: IngestManager.fetchDeviceData() will use ipAddress for outbound device communication, and the value was previously a free-form Type.String() accepting URL schemes, paths, credentials, whitespace and CRLF.
  • Use pattern rather than format because ajv-formats is not registered in this project, so format keywords are documentation-only and are not enforced; pattern is a core JSON Schema keyword and is always applied.
  • Add a SECURITY note near the fetchDeviceData TODO in src/ingest_manager.ts reminding that any real implementation must additionally reject private/reserved/loopback/link-local ranges before making outbound requests.
  • Extend src/api_validation.test.ts with a valid-IPv6 acceptance case and a parametrised set of malformed/injection inputs (scheme, path, port, hostname, out-of-range octets, trailing space, CRLF) that must be rejected with 400.

Test plan

  • Tests pass (npm test — 358 passed, 18 suites)
  • TypeScript compiles (npm run typecheck)
  • Lint clean (npm run lint — 0 errors; pre-existing any warnings only)
  • Prettier clean (npx prettier --check on touched files)
  • Valid IPv4 (127.0.0.1) and IPv6 (2001:db8::1) reach the handler (501), malformed inputs are rejected (400)

Closes #250

🤖 Generated with Claude Code

… SSRF

The NewIngest TypeBox model accepted ipAddress as a free-form string with no
format or pattern constraint. IngestManager.fetchDeviceData will use this value
for outbound device communication, so an unvalidated value is an SSRF and
request-injection risk. Restrict the field with a strict IPv4/IPv6 pattern at
the schema boundary (ajv-formats is not registered, so `pattern` is used rather
than `format`, which would not be enforced), and document the additional
private/reserved-range guard any future device-communication implementation
must add.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@birme

birme commented Sep 28, 2026

Copy link
Copy Markdown
Contributor Author

Code Review — Verdict: LGTM

Reviewed by a separate code-reviewer invocation (not the implementer). Summary: adds a correct, ReDoS-safe IPv4/IPv6 pattern to NewIngest.ipAddress, closing the schema-boundary gap that let arbitrary strings (URLs, paths, CRLF) reach the SSRF-prone fetchDeviceData path; includes a SECURITY note and thorough regression tests. No Blocking or Warning items. CI green (lint, pretty, ts, unittests).

This PR is self-authored by the automation account, so GitHub blocks a state-bearing self-approval; recording the verdict as this marker and merging via admin per the daily-backlog-pr skill.

@birme
birme merged commit 2060c9c into main Sep 28, 2026
4 checks passed
@birme
birme deleted the security-audit/250-ingest-ipaddress-validation branch September 28, 2026 07:46
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.

Security: ipAddress field in ingest model has no format validation — SSRF risk when device communication is implemented

2 participants