From 30523aa3314086628c1114049e066f7f75f3e690 Mon Sep 17 00:00:00 2001 From: Pranav Verma Date: Sat, 17 Oct 2026 15:27:18 +0000 Subject: [PATCH] Explain the project at a glance in the README and refresh the roadmap --- CHANGELOG.md | 1 + README.md | 73 +++++++++++++++++++++++++++++++++++++++++++++++++ docs/ROADMAP.md | 30 ++++++++++++++------ 3 files changed, 96 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f8c6617..d0d5f85 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ follow [Semantic Versioning](https://semver.org/) from the first tagged release. - CISA secure-by-design mapping in `docs/assurance.md`, including why monitor mode is the default. ### Changed +- README: a plain-language "At a glance" section (what it is, who it is for, how you use it) and common questions. Roadmap: measured results next to the targets, a corrected coverage floor, and an "After 0.1" list. - README: v0.1.0 status, install section (container and release archive), a "What it does not do" section, governance and citation links. `docs/releasing.md` describes the signed-tag, pull-request release flow. - The startup message that says monitor mode does not block is now a warning, so it shows at `-log-level warn`. - `SECURITY.md` supported-versions table; `docs/releasing.md` states that breaking changes may land in a minor release below 1.0. diff --git a/README.md b/README.md index 63b41e8..f5fa0d1 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,79 @@ reach the host. It is a **compensating control**, not a fix: patch, remove > the public surface may still change in a minor release, always noted in the > [changelog](CHANGELOG.md). Start in monitor mode before relying on it. +## At a glance + +Say you run an old web application, such as a plant's reporting dashboard, that +uses a vulnerable Log4j. The vendor cannot patch it until next year, or the server +is too old to upgrade. An attacker who sends a request containing something like +`${jndi:ldap://...}` can make that application reach out and run what comes back. + +LogShield is a gatekeeper you put **in front of** that application: + +```mermaid +flowchart LR + A[Clients and attackers] --> L[LogShield
inspects every request] + L -- clean --> V[Your vulnerable application] + L -- attack --> X[403, logged and counted
never reaches the application] +``` + +Every request passes through LogShield first. It works out what Log4j would make +of each part of the request, including the disguised forms, and refuses the ones +that would trigger a lookup. Everything else goes through unchanged. You change +the network path, not the vendor's software. + +**Who it is for:** teams that run Java applications they cannot patch yet, +especially in operational technology (OT/ICS) and other legacy environments, and +security engineers who need a documented compensating control for them. + +**How you use it:** + +1. [Install it](#install) (one container or one static binary) and give it the + address of the application it protects. +2. Make the application reachable **only** through LogShield: bind it to + localhost, or firewall it so only LogShield can reach it. This is the step that + makes the protection real. +3. Run in **monitor mode** for a few days. It records what it would block and + blocks nothing, so you can check it against your real traffic. +4. Switch to **block mode**. Attack requests now get a `403` and never reach the + application. +5. Watch the [metrics and logs](docs/observability.md), and keep a plan to patch + or retire the application, because this is a stopgap. + +A longer walk-through, with deployment patterns for systemd, Kubernetes and nginx, +is in [docs/deployment.md](docs/deployment.md). + +## Common questions + +**Does it replace patching?** No. It is a compensating control for one attack +class. Patch Log4j (2.17.1 or later), remove the `JndiLookup` class, or retire the +host as soon as you can. + +**Does it slow my application down?** In the load test it added about 0.7 ms at +the 99th percentile for a single client on a small machine +([load report](docs/load-report.md)). Measure it on your own traffic. + +**What if LogShield goes down?** It sits in the request path, so a single instance +is a single point of failure. Run it under a supervisor (systemd or Kubernetes +restart policies), use the health endpoints, and run more than one instance where +availability matters. What it does when inspection itself fails is a setting you +choose: `on_error: closed` (refuse) or `open` (forward, counted in a metric). + +**Does it work with HTTPS?** Yes. It can terminate TLS itself (HTTP/2 included) or +sit behind a TLS terminator such as nginx. Traffic it cannot decrypt cannot be +inspected. + +**Which Log4j versions was it tested against?** The lab validation used Log4j +2.14.1 on OpenJDK 8. Other versions and JDKs are not covered by that result; see +the [limits](docs/lab.md). + +**Is it a general web application firewall?** No. It looks for Log4Shell-class +payloads only, and it does not replace a WAF. + +**I found a bypass.** Please report it privately, as described in +[SECURITY.md](SECURITY.md). Confirmed bypasses become regression tests and are +credited. + ## What it does not do Read this before deploying. LogShield is a compensating control for one attack diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md index 579f75d..69cc7ff 100644 --- a/docs/ROADMAP.md +++ b/docs/ROADMAP.md @@ -5,14 +5,16 @@ measurable. ## Targets -These are goals to be confirmed by measurement, not claims. +These started as goals and were then confirmed by measurement (details in the +[evaluation report](eval/report.md), [lab report](lab-report.md) and +[load report](load-report.md)). -| Metric | Target | -|---|---| -| Missed payloads in in-scope bypass classes | 0 | -| False-positive rate on the benign corpus | < 0.1% | -| p99 added latency | < 5 ms | -| Engine line coverage floor | >= 90% | +| Metric | Target | Result at v0.1.0 | +|---|---|---| +| Missed payloads in in-scope bypass classes | 0 | 0 of 165 corpus entries; 107 of 107 real Log4j JNDI attempts flagged in the lab | +| False-positive rate on the benign corpus | < 0.1% | 0 of 100,111 (95% upper bound below 0.0038%) | +| p99 added latency | < 5 ms | 0.7 ms, one client | +| Coverage floors (total / engine) | 97% / 98% | 97.5% / 99.5% | ## Step 1: inspection engine @@ -43,7 +45,19 @@ These are goals to be confirmed by measurement, not claims. ## Step 5 -- [ ] Short technical write-up of methodology and results +- [ ] Technical write-up of methodology and results. Drafted as a four-part series (what and why, how it works, how it was tested, how to use it); the links go here once published. + +## After 0.1 + +Candidates, roughly in order of value. None is promised. + +- **Outside review.** Invite someone who knows Log4j or OT security to try to bypass it; every confirmed bypass becomes a corpus entry. +- **Wider validation.** Run the lab against more Log4j versions (such as 2.15 and 2.16) and more JDKs, and extend the differential to other logging paths. +- **Measurements still missing.** Memory under concurrent load and behaviour on production-shaped traffic ([performance](performance.md)). +- **Control self-test canary** (Step 4). +- **Container health check.** The distroless image has no shell, so a plain `docker run` has no built-in `HEALTHCHECK`; a small `-healthcheck` mode would close that gap. +- **SLSA Build Level 3**, by moving the release build into an isolated reusable workflow ([assurance](assurance.md)). +- **A second maintainer**, which also raises the Code-Review and OpenSSF scores. ## Working agreement