google / google/capsem

Security ledger event_json.decision says allow on blocked HTTP and DNS requests

Open
#203 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Rust
Stars
72
Forks
13
Avg merge
1d 2h
Merged PRs (30d)
5

Description

## Observed

On a real VM (Kingslanding run `20260911-162608-1e42bc-focus-test`), a corp rule `http.host == "egress.capsem.test" && http.path == "/secret"` with `action = "block"` refused the request (client got a non-zero exit, nothing reached the upstream transcript), and a `dns.qname.matches(...)` block rule refused a query. The `security_rule_events` rows for both carry the correct row-level `rule_id` and `rule_action = block`, but the stored `event_json.decision.effective` is `"allow"` on every one of those rows:

```
http=[('egress.capsem.test', '/secret', 'allow'), ('egress.capsem.test', '/secret', 'allow'), ...]
dns=[('probe..attacker.test', 'allow'), ...]
```

Network boundary rows do not have this problem: `security_engine/network/ledger.rs` runs `prepare_evaluated_event_for_security_rule_ledger` and `apply_event_decision_to_enforcement` before serializing, so `test_policy.py` can assert `decision.effective == "block"`.

## Why it matters

`event_json` is what a responder reads when the rules have changed since the event. A snapshot that says `allow` for a request the product blocked is wrong evidence, and the two boundary families disagree on what the field means.

## Expected

One contract: `event_json.decision` on a security rule row reflects the effective decision at the time the row was written, for HTTP, DNS, MCP, file and network alike. Either the HTTP/DNS emitters (`TelemetryHook`, DNS handler emission via `emit_evaluated_security_rules`) serialize after applying the decision like the network path, or the field is dropped from non-network rows and documented as row-level `rule_action` only. Tests: ironbank HTTP and DNS block proofs assert the field, and a Rust unit test on the emitter.

Contributor guide

Open the contributing guide

Research direction

Compare security_engine/network/ledger.rs with the HTTP TelemetryHook and DNS emission through emit_evaluated_security_rules, then inspect test_policy.py and the ironbank HTTP/DNS block proofs. Verify where event_json.decision is serialized and how the network path applies the effective decision. Done means the agreed contract is covered by the HTTP and DNS assertions plus a Rust emitter unit test.

Written by the indexing model from the issue text.

Assessment

Tech stack
python, rust
Domain
backend, security, testing-qa
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.