Back to The Vault

Aegis: From a Security Finding to an Explanation You Can Check

Follow one scan through Aegis to see how network checks become findings, where Gemini helps, and why a readable report still needs traceable evidence.

September 22, 2025•Updated October 17, 2026•9 min read•

“Missing security header.” Now what?

Imagine opening a report with that finding. You still need to know which response was checked, what was absent, and what to investigate next. A red severity badge doesn't answer those questions.

Aegis connects two jobs: collecting structured observations about an application and explaining those observations in plain language. The scanner uses Python and FastAPI; a separate Gemini call produces a short narrative from the findings. Online Boutique, the sample shopping application used in the GKE Turns 10 hackathon, is the intended target.

Let's follow one illustrative missing-header finding through the published backend. Along the way, we'll separate what the checks establish from what a report might tempt us to conclude.

The useful promise is traceability: you should be able to work backward from an explanation to the finding that supports it.

Follow one scan from request to report

Follow the flow

One scan, four stages

Choose a step to see what happens and why it matters.

FastAPI · scan ID and background task

The API creates a scan record in memory and schedules the scanner as a background task. The initial response gives the client a scan ID rather than waiting for every check to finish.

The design lessonAn accepted scan is still work in progress. The client needs a separate way to retrieve its state.
Step 1 of 4

The diagram below shows the backend's scan and reporting paths. Indigo handles the request, amber represents checks, slate holds findings, and teal adds explanation. The AI call comes after a completed scan; it does not perform the underlying network checks.

Notice that the target and the scanner are different applications. GKE is where the demo target is intended to run. The deployment scripts package the scanner backend for Cloud Run. “A scanner for GKE” doesn't mean its scanning logic is itself a Kubernetes controller.

Start with a small, checkable observation

Suppose an illustrative response looks like this:

HTTP/1.1 200 OK
Content-Type: text/html
X-Content-Type-Options: nosniff

Aegis compares the response headers with a fixed list that includes Content-Security-Policy, Strict-Transport-Security, X-Frame-Options, X-Content-Type-Options, and Referrer-Policy. For each absent header, it records a finding with a title, description, severity, affected endpoint, recommendation, and optional CWE identifier.

In this example, the CSP check would produce a missing-header finding. The rule assigns its severity; Gemini does not choose it.

Pause here: does the missing header prove an exploitable vulnerability?

The observation establishes that this response lacked the checked header. It does not demonstrate an exploit, describe every response the application serves, or establish the application's overall security. The finding is a starting point for investigation. A useful report preserves that distinction instead of turning an absent header into a claim that an attack succeeded.

That distinction matters even for the finding count. The scanner also records successful service discovery as low-severity findings. Total findings therefore includes observations about reachable services, not just suspected weaknesses.

What “discovery” means in this prototype

Online Boutique gives the project a known application shape. The scanner contains a table of 11 named services with expected ports and protocols. It takes the host from the submitted URL and checks those configured locations.

This is a practical shortcut for a demo with a known target. It is not general discovery of an arbitrary Kubernetes cluster. A connection to one host and port doesn't tell the scanner which pods exist behind that address, how requests move between them, or whether every internal service is externally reachable.

The gRPC reachability helper makes an ordinary TCP connection. That answers a narrower question—can a connection be opened?—than a successful protocol-specific gRPC call would.

Trade-off: Known service map or general discovery?
Decision: Use a fixed target map to make the prototype's scope concrete

A configured map keeps the scanning workflow small and understandable. The cost is that the result depends on how that particular deployment exposes its services. General discovery would need a reliable source of service identity and topology, followed by checks appropriate to each protocol.

Why some findings need another check

The source makes an especially useful teaching example of the gap between a check's name and its evidence.

CheckWhat it doesWhat remains unknown
HTTP header checkLooks for a name in one response's headersWhether the relevant protection is appropriate and effective
gRPC reachabilityOpens a TCP connection to a configured portWhether the endpoint actually implements the expected service
TLS checkAttempts a TLS connection with certificate verification disabledCertificate trust and hostname validation
Reflection checkReuses the connection test as a simplified heuristicWhether a gRPC reflection request actually succeeds

The reflection row is the clearest example: reaching a port is not evidence that reflection is enabled. A report should preserve that uncertainty, or a follow-up check should resolve it.

This is a broader lesson for agent applications: naming a tool after a capability doesn't make every result evidence of that capability. Read what the tool actually observes.

Where does Gemini help?

The summary endpoint gathers each finding's severity, title, and affected endpoint, adds the target and total count, and asks Gemini for a concise explanation with priorities and recommendations. The prompt requests a summary under 200 words for technical and nontechnical readers.

That is a useful translation task. It can turn a long list into a place to start. It also creates a boundary: the model sees the supplied descriptions, not an independent replay of the scan. The current summary prompt does not include full response captures or every field in the finding record.

A good explanation might connect a finding to its likely impact and suggest what to verify next. It should not invent an exploit chain, silently upgrade a heuristic to a confirmed result, or describe services the scan never reached.

The published implementation calls Gemini directly. Although the original design description mentions LangGraph and Vertex AI, the inspected backend follows ordinary Python calls and uses the Google generative AI client. The story here follows that implemented path.

The less visible design decision: who remembers the scan?

Starting a scan returns an ID while a FastAPI background task runs. A client can ask for results using that ID, and request an AI summary once the status is completed. This keeps the long-running work separate from the initial response.

The backend's primary lookup is an in-memory dictionary. Completed results can also be written to Firestore when a database client is available. However, the results endpoint reads the dictionary; it doesn't reload a missing scan from Firestore.

Why does that matter? Imagine one process accepts the scan and another receives the polling request. A database copy doesn't automatically make those processes share their in-memory state. A restart raises the same question about retrieving earlier work.

For a production version, durable job state and a worker model would need explicit design. The prototype is valuable because it makes that boundary visible: background execution, persistence, and result retrieval are three different responsibilities.

What would make this report more trustworthy?

I'd start with four targeted tests. Give the header check a controlled response with known headers. Confirm that a reachable port without gRPC reflection doesn't become a confirmed reflection finding. Make summary generation fail and check that the original findings remain available. Finally, restart the process and test what the results API can recover.

Those are proposed tests, not completed benchmark results. They address what the user actually depends on: a finding means what it says, an AI failure doesn't erase evidence, and the scan ID still leads somewhere useful.

The idea worth carrying forward

Aegis is most useful as a lesson in evidence before explanation. Deterministic checks produce structured observations; a model helps a reader navigate them. The quality of that explanation is bounded by the quality and precision of the observations underneath it.

When building a similar tool, begin with one finding you can reproduce and explain completely. Then add breadth. A smaller report that tells you exactly what was checked is easier to trust than a larger one whose certainty exceeds its evidence.

Explore the implementation

This walkthrough follows the public source at revision 65cae84:

Cite this page
Kapoor, Saksham. "Aegis: From a Security Finding to an Explanation You Can Check." The Vault (blog). September 22, 2025. https://saksham-kapoor.vercel.app/vault/aegis-gke-security-agent

Related Posts

Press ⌘+K to search