v0.3.0-rc2: graph SQLi removal (closes last G-audit Critical) + README refresh#3
Merged
Conversation
…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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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:601previously routed any input that didn't match the MATCH-translation patterns throughexecute_raw_sql, giving any caller with thegraph:readABAC permission a primitive to run arbitrary SQL (DROP TABLE,ATTACH DATABASE,INSTALL httpfs; LOAD httpfs; COPY ... TO 'http://attacker/', etc.).Changes:
src_id,wc,edge_type,limitare now bound via duckdb'sparams!.;,--,/*,DROP,ATTACH,INSTALL,COPY,PRAGMA, etc.) outside quoted regions, so a prefix-only translator can't be exploited viaMATCH (n:ship); DROP TABLE entities -- RETURN n.GRAPH_RESULT_HARD_CAP(10,000) regardless of user-suppliedLIMIT.strip_quoted_regionshelper 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 rejectedtest_17_quote_injection_in_src_id—' OR 1=1 --inside a value is treated as a literal, returns 0 rowstest_18_limit_capped— userLIMIT 10^9silently capped at 10,000test_19_edge_type_allowlist— unknown edge_type returns error, not raw SQLREADME refresh (
docs(README): refresh for v0.3.0-rc1)Procurement-visible update reflecting v0.3.0-rc1's hardening:
mTLS | OIDC | Argon2idsecurity badge.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— unusedlet conn_arc = { ... };block returning().What this PR closes
jwks_uriignored (P Critical)After this merges, every Critical from both audits is closed in master.
Test plan
cargo fmt --all -- --check— cleancargo clippy --all --all-features --tests -- -D warnings— cleancargo test -p orp-storage --all-features— 21/21 graph_engine tests passingDeferred to follow-up PRs
feat/v0.3.0-rate-limit. Requires conflict resolution against rc1.enqueue_outboundis wired but the push-on-error path needs the call site. Wip onfeat/v0.3.0-federation-outbox.feat/v0.3.0-bincode-2x.~/.local/share/orp/audit-key.ed25519.🤖 Generated with Claude Code