This repository contains the complete implementation and artifacts from the Secure Agentic Coding Codelab. It serves as a hands-on learning blueprint for security engineers and AI developers looking to understand the threat landscape of LLM-based agents and how to secure them.
Traditional application security focuses on securing APIs, databases, and authentication endpoints. However, AI agents introduce a new class of runtime risks: they dynamically select tools, execute commands, parse unstructured input, and make decisions semi-autonomously.
This lab is designed to teach how to transition from traditional application security to Agentic Security, implementing a multi-layered defense-in-depth posture that spans static analysis, threat modeling, test-driven development (TDD), and runtime interception.
Instead of modeling simple data flows, this lab demonstrates how to apply the STRIDE framework specifically to ReAct agent architectures. This highlights unique agent vectors:
- Spoofing & Elevation of Privilege: How LLM instruction-following can be tricked into spoofing
user_idvalues or bypassing basic string checks (e.g. prefix matches). - Tampering & TOCTOU: Understanding race conditions (Time-of-Check to Time-of-Use) when agents manage volatile state across tool runs.
- Read the completed model in threat_model.md.
You'll learn how to build a robust safety net around the agent. The lab demonstrates security enforcement at four distinct boundaries:
- Developer Context Gate: Grounding developer/coding agents (using CONTEXT.md) to enforce secure-by-default paradigms.
- Static Commit Gate: Stopping credential leaks automatically via Semgrep and pre-commit hooks.
- Runtime Interception Hook: Intercepting and validating tools before they are sent to the execution layer.
- Tool-Level Guardrails: Writing robust Python logic with strict type checking and state isolation.
graph TD
User([User Prompt]) --> Agent[LLM Agent / ADK 2.0]
subgraph 1. Coding & Planning
Context[CONTEXT.md Standards]
end
subgraph 2. Static Commit Hook
PreCommit[Pre-Commit Config] --> Semgrep[Semgrep Rules]
end
subgraph 3. Infrastructure Hooks
PreToolHook[PreToolUse Hook] --> ValidateScript[validate_tool_call.py]
end
subgraph 4. Application Logic
Tool[redeem_discount Tool] --> StateCheck[Business Logic Guardrails]
end
Agent -->|Invokes Tool| PreToolHook
ValidateScript -->|Approved| Tool
Tool -->|Accesses State| StateCheck
style Context fill:#f9f,stroke:#333,stroke-width:2px
style Semgrep fill:#ffcccb,stroke:#333,stroke-width:2px
style ValidateScript fill:#ffeb3b,stroke:#333,stroke-width:2px
style StateCheck fill:#90caf9,stroke:#333,stroke-width:2px
Hardcoded keys are a major vulnerability in AI development. In this lab, you'll learn to:
- Write custom Semgrep rules that target specific pattern matches for sensitive credentials (e.g., Google
AIzaSy...keys). - Integrate them into a local pre-commit hook to block insecure commits before they reach remote repositories.
How do you prevent an agent from running harmful commands at runtime, even if it is tricked by prompt injection?
- Configure
PreToolUsehooks in hooks.json. - Build a command validator script validate_tool_call.py that acts as an out-of-band firewall, parsing tool parameters (like shell commands) and blocking destructive executions (e.g., preventing arbitrary shell command execution).
Rather than verifying security manually, you'll learn to write a dedicated security test suite using pytest in test_agent.py. These tests assert:
- Single-Use Enforcement: Discount codes cannot be redeemed more than once.
- Privilege Segregation: Guest accounts (e.g.,
guest_*) are rejected. - Strict State Isolation: Using Pytest fixtures to reset state between tests to guarantee zero test cross-contamination.
Every file in this project represents an educational lesson in agentic safety:
| File / Directory | Concept / Takeaway | Description |
|---|---|---|
app/agent.py |
Secure Tool Design | Demonstrates robust parameter validation (rejects invalid codes, prevents guest access) alongside an intentional simulated vulnerability (hardcoded mock API key) to trigger security gates. |
.agents/CONTEXT.md |
Developer Alignment | Defines rules that developer/agent models must follow, ensuring secure coding paradigms are established from the outset. |
.agents/hooks.json |
Runtime Interception | Configures infrastructure-level hooks to intercept tool usage before execution. |
scripts/validate_tool_call.py |
Security Firewalls | Python script executing out-of-band logic to inspect and block destructive tools. |
.semgrep/rules.yaml |
Static Scanning | Custom rule patterns targeting Google API Studio credential signatures. |
.pre-commit-config.yaml |
Git Hooks | Automates the local Semgrep scan, preventing vulnerabilities from leaking to version control. |
tests/test_agent.py |
TDD & Assertions | Pytest security test suite asserting on authorization and single-use business constraints. |
threat_model.md |
STRIDE Framework | Full STRIDE analysis documenting agent threat vectors and their respective mitigations. |
- Scaffolded an ADK 2.0 ReAct agent project using
uvx google-agents-cli. - Configured
pyproject.tomland verified virtual environment configuration viauv.
- Defined a rule to scan for credentials matching
AIzaSy[A-Za-z0-9_\-]*. - Added the pre-commit configuration.
- Demonstration: When a developer attempts to commit
agent.pycontaining the mock key, the commit is blocked by the Git hook:git commit -m "feat: add API key" # Semgrep Scan...........................................................Failed # - hook id: semgrep-local # - exit code: 1 # Security violation: Hardcoded Google API key detected.
- Formulated security boundary tests first.
- Implemented the
redeem_discounttool. - Ran and passed the security test suite:
uv run pytest tests/test_agent.py # ======================== 3 passed in 3.57s ========================
- Started the ADK dev server to inspect the agent graph and tools visually:
uv run adk web app --host 127.0.0.1 --port 8080
| Problem | Root Cause | Fix Applied |
|---|---|---|
uv sync fails on Windows |
OneDrive filesystem blocks hardlinks | $env:UV_LINK_MODE="copy" |
Edge.chain(...) AttributeError |
Method doesn't exist in ADK 2.0 | Replaced with edges=[("START", agent)] tuple notation |
SessionNotFoundError in dev server |
App(name="shopping_assistant") mismatches folder name app |
Changed to App(name="app") |
| Pre-commit hook not finding Semgrep | Hook runs from repo root, one level above the project | Used uv run --directory shopping-assistant semgrep |
agents-cli playground fails |
CLI globs current directory contents into adk web args |
Use uv run adk web app directly instead |
API key api_key= not a Gemini field |
ADK 2.0 Gemini class dropped api_key from its schema |
The # type: ignore suppresses the Pydantic validation warning for the codelab demo |
- Python 3.11–3.13
uvuvx google-agents-cli- A real
GEMINI_API_KEYfrom Google AI Studio
git clone https://github.com/xylaes/secure-agent-lab.git
cd secure-agent-lab/shopping-assistant
$env:UV_LINK_MODE="copy"
uv syncuv run pytest tests/test_agent.pyuv run adk web app --host 127.0.0.1 --port 8080
# Access: http://127.0.0.1:8080/dev-ui/?app=app