Skip to content

v0.3.0-rc2: graph SQLi removal (closes last G-audit Critical) + README refresh#3

Merged
shieldofsteel merged 3 commits into
masterfrom
feat/v0.3.0-rc2
May 1, 2026
Merged

v0.3.0-rc2: graph SQLi removal (closes last G-audit Critical) + README refresh#3
shieldofsteel merged 3 commits into
masterfrom
feat/v0.3.0-rc2

Conversation

@shieldofsteel

Copy link
Copy Markdown
Owner

Summary

Two clean commits on top of v0.3.0-rc1:

S1 — graph SQLi removal (fix(security): remove raw-SQL fallback from cypher_query)

Closes the last Critical finding from the post-v0.2.0 audit (G's report). crates/orp-storage/src/graph_engine.rs:601 previously routed any input that didn't match the MATCH-translation patterns through execute_raw_sql, giving any caller with the graph:read ABAC permission a primitive to run arbitrary SQL (DROP TABLE, ATTACH DATABASE, INSTALL httpfs; LOAD httpfs; COPY ... TO 'http://attacker/', etc.).

Changes:

  • Raw-SQL fallback removed entirely.
  • Every interpolation parameterised — src_id, wc, edge_type, limit are now bound via duckdb's params!.
  • New defensive pre-filter rejects inputs containing forbidden tokens (;, --, /*, DROP, ATTACH, INSTALL, COPY, PRAGMA, etc.) outside quoted regions, so a prefix-only translator can't be exploited via MATCH (n:ship); DROP TABLE entities -- RETURN n.
  • Result-set size hard-capped at GRAPH_RESULT_HARD_CAP (10,000) regardless of user-supplied LIMIT.
  • New strip_quoted_regions helper so quote-injection inside property values ({id: "' OR 1=1 --"}) doesn't false-positive the forbidden-token filter.

Tests (4 new + 21/21 graph_engine total passing):

  • test_16_unsupported_cypher_rejected — 4 known SQLi payloads all rejected
  • test_17_quote_injection_in_src_id' OR 1=1 -- inside a value is treated as a literal, returns 0 rows
  • test_18_limit_capped — user LIMIT 10^9 silently capped at 10,000
  • test_19_edge_type_allowlist — unknown edge_type returns error, not raw SQL

README refresh (docs(README): refresh for v0.3.0-rc1)

Procurement-visible update reflecting v0.3.0-rc1's hardening:

  • Badges: tests 1122 → 1362, adapters 34 → 39, new mTLS | OIDC | Argon2id security badge.
  • Tagline: "fuses 39+ protocols into one cryptographically-signed real-time picture".
  • "What it is" line lists the new protocols (CoT, KLV, CCSDS+SGP4, HL7, Kafka, NATS) and v0.3.0 hardening primitives.
  • Comparison tables: 34 → 39 adapter counts.
  • Protocol Support: split into bulleted categories with shipped-protocol details.
  • NEW Security Posture section: 14-row capability table for inbound TLS / federation mTLS / Ed25519 payload signing / replay protection / confidence cap / OIDC JWKS / Argon2id keystore + passwords / signed audit log / SSRF defence / WS identity propagation / notification circuit breaker / CSRF entropy. Plus "closed in v0.3.0" and "pending v0.4" lists.
  • Build section: cargo test count 1,122 → 1,362.
  • Contributing wishlist: removed "(started)" tags from KLV / Kafka / CCSDS / HL7 (all shipped); added Link 16 / STANAG 4586 to wishlist.

Plus a clippy-fix commit

Pre-existing lints that didn't trip in rc1's clippy run but surface under rc2's clippy 1.91:

  • graph_engine.rs:1148 — manual &rhs[1..]rhs.strip_prefix('\'').
  • cli_smoke.rs:50 — unused let conn_arc = { ... }; block returning ().

What this PR closes

Audit finding Status before rc1 Status after rc1 Status after rc2
Federation no TLS/peer-auth (P Critical) open ✅ closed by F1 (rc1)
Audit signing key ephemeral (P Critical) open ⏳ chain landed; key persistence is F2 (rc1)
Inbound HTTP plain TCP (P Critical) open ✅ closed by F3 (rc1)
OIDC jwks_uri ignored (P Critical) open ✅ closed by F4 (rc1)
Notifications SSRF (G Critical) open ✅ closed by S3 (rc1)
WebSocket JWT identity discarded (G Critical) open ✅ closed by S2 (rc1)
graph_engine SQL injection (G Critical) open open (deferred) ✅ closed by S1 in this PR

After this merges, every Critical from both audits is closed in master.

Test plan

  • cargo fmt --all -- --check — clean
  • cargo clippy --all --all-features --tests -- -D warnings — clean
  • cargo test -p orp-storage --all-features — 21/21 graph_engine tests passing
  • CI to confirm cross-platform (Linux + macOS) full workspace test

Deferred to follow-up PRs

  • S5 rate limiter — LRU bound + XFF trust gate + ingest separate ceiling. Wip on feat/v0.3.0-rate-limit. Requires conflict resolution against rc1.
  • C federation outbox wire-upenqueue_outbound is wired but the push-on-error path needs the call site. Wip on feat/v0.3.0-federation-outbox.
  • E bincode 1→2 migration — clears RUSTSEC-2025-0141 informational warning. Wip on feat/v0.3.0-bincode-2x.
  • F2 audit signing key persisted to ~/.local/share/orp/audit-key.ed25519.
  • F5 CSRF cookie HMAC + constant-time compare.
  • F6 SMTP STARTTLS implementation.
  • F7 at-rest encryption opt-in for DuckDB + RocksDB.
  • F8 sanctions list signature verification on load.
  • F9 TLS backend unification — drop native-tls from orp-connector.

🤖 Generated with Claude Code

Prince and others added 3 commits May 1, 2026 21:43
…ity posture section

Updates after the v0.3.0-rc1 merge:
- Badges: tests 1122 → 1362, adapters 34 → 39, new mTLS|OIDC|Argon2id security badge.
- Tagline: 30+ → 39+ protocols, mention 'cryptographically-signed real-time picture'.
- 'What it is' line: list new protocols (CoT, KLV, CCSDS+SGP4, HL7, Kafka, NATS) and call out the v0.3.0 hardening primitives explicitly.
- Comparison tables: 34 → 39 adapter counts in the SQLite/Postgres/Lattice/Maven and TAK/FreeTAK matrices.
- Protocol Support: split into bulleted categories with shipped-protocol details (was a single paragraph claiming 34 adapters).
- New SECURITY POSTURE section: capability table for inbound TLS, federation mTLS, Ed25519 payload signing, replay protection, confidence cap, OIDC JWKS, Argon2id keystore + passwords, signed audit log, SSRF defence, WS identity propagation, notification circuit breaker, CSRF entropy. Includes 'closed in v0.3.0' and 'pending v0.4' lists.
- Build section: cargo test count 1,122 → 1,362.
- Contributing wishlist: removed 'started' tags from KLV / Kafka / CCSDS / HL7 (all shipped in v0.2.0); added Link 16 / STANAG 4586 to wishlist.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ph SQLi

POST /api/v1/graph previously routed any input that didn't match the
MATCH-translation patterns through execute_raw_sql, giving any caller
with the graph:read ABAC permission a primitive to run arbitrary SQL
(DROP TABLE, ATTACH DATABASE, INSTALL httpfs+COPY exfil, etc.).

This removes the fallback entirely and parameterises every interpolation:
- src_id, wc, edge_type, limit are now bound via duckdb's params! rather
  than format!()'d into the SQL string.
- A defensive pre-filter rejects inputs containing forbidden tokens
  (DROP, ATTACH, INSTALL, COPY, ;, --, /*, etc.) outside quoted regions,
  so an attacker can't smuggle injection through a bypass like
  'MATCH (n:ship); DROP TABLE entities -- RETURN n' which the prefix-only
  translators would otherwise accept.
- Result-set size is hard-capped at GRAPH_RESULT_HARD_CAP (10,000)
  regardless of any user-supplied LIMIT.

New tests:
- test_16_unsupported_cypher_rejected: 4 known SQLi payloads all rejected
- test_17_quote_injection_in_src_id: ' OR 1=1 -- inside a property value
  is treated as a literal (zero rows) and never breaks out
- test_18_limit_capped: user LIMIT 10^9 is silently capped at 10,000
- test_19_edge_type_allowlist: unknown edge_type returns error, not raw SQL
- plus strip_quoted_regions unit test

21/21 graph_engine tests passing.

Closes G-audit Critical: graph_engine.rs:601 raw-SQL fallback.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Pre-existing clippy lints that didn't trip in v0.3.0-rc1 but surface under
clippy 1.91 with -D warnings on the rc2 build. Both are mechanical fixes
that don't change behaviour:
- graph_engine.rs:1148 — `if rhs.starts_with('\\'') { let after = &rhs[1..]; ... }`
  → `if let Some(after) = rhs.strip_prefix('\\'') { ... }` (idiomatic).
- cli_smoke.rs:50 — `let conn_arc = { side_effect_block_returning_unit };`
  → bare block (the binding was unused; the trailing `let _ = conn_arc;` was a tell).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@shieldofsteel shieldofsteel merged commit 210c63a into master May 1, 2026
4 of 7 checks passed
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.

1 participant