Ayush-Kumar0207/patchcascade-soc
<div align="center">
๐ก๏ธ PatchCascade SOC
Autonomous Cyber-Resilience Through Reinforcement Learning
     
Train AI agents to manage vulnerability patches across enterprise networksโwithout crashing production.
Quick Start โข The Challenge โข Architecture โข Grading Logic โข API Reference โข Contributors
๐ Meta PyTorch OpenEnv Hackathon 2026 Submission
</div>
๐ฌ Research Motivation
Modern enterprise networks face a critical unsolved problem: how to autonomously patch security vulnerabilities without causing service outages. This is a fundamentally sequential decision-making problem with:
- Dependency-aware constraints: Patching node A may crash nodes B, C, D
- Multi-objective optimization: Minimize both security risk AND downtime
- Dynamic threat landscapes: New zero-day vulnerabilities emerge unpredictably
- Cascading failure risks: One wrong action can take down entire infrastructure
PatchCascade SOC provides a research-grade RL environment that captures the full complexity of this problem. Unlike toy grid-worlds or game environments, PatchCascade models real SOC workflows with:
- Realistic network topologies with tiered criticality and service dependencies
- CVSS-based vulnerability scoring matching industry-standard severity ratings
- Dense reward shaping that provides continuous learning signal
- Dynamic events including exploit spreading and zero-day injection
- Multi-dimensional evaluation across completion, efficiency, safety, and strategy
This environment is designed to train agents that could eventually assist human SOC analysts in making high-stakes patching decisions.
๐ Theoretical Foundation
Our reward design implements potential-based reward shaping (Ng, Harada & Russell, 1999), which provides dense learning signal while preserving optimal policy invariance. The key insight is:
R'(s, a, s') = R(s, a, s') + ฮณฮฆ(s') - ฮฆ(s)Where ฮฆ(s) is our potential function (total penalty from risk + downtime). This guarantees that any policy optimal under the shaped reward is also optimal under the original sparse reward.
Key References:
- Ng, A. Y., Harada, D., & Russell, S. (1999). Policy invariance under reward transformations. ICML.
- Sutton, R. S., & Barto, A. G. (2018). Reinforcement Learning: An Introduction. MIT Press.
- Mnih, V., et al. (2015). Human-level control through deep reinforcement learning. Nature.
๐ฏ The Problem: The Patching Paradox
"Every unpatched CVE is a ticking time bomb. But every patch is a potential outage."
Security teams face an impossible tradeoff:
The real nightmare? Modern infrastructure has dependencies. Patch your database, and suddenly your web servers crash. Take down authentication, and your entire stack follows. One wrong move triggers a cascade failure that costs millions.
PatchCascade SOC trains AI agents to navigate this paradoxโlearning to patch vulnerabilities in the optimal order while minimizing downtime and avoiding catastrophic cascades.
๐ก Why PatchCascade?
โจ Feature Highlights
๐ข Tiered Asset Management
Not all servers are equal. Our environment models real-world criticality:
๐ Dynamic Dependency Graph
Real-time cascade failure simulation with hard and soft dependencies:
graph TD
LB[๐ต lb-primary-01<br>Tier 2] -->|soft| W1[๐ก web-frontend-01<br>Tier 2]
LB -->|soft| W2[๐ก web-frontend-02<br>Tier 2]
W1 -->|hard| A1[๐ก app-server-01<br>Tier 2]
W2 -->|hard| A2[๐ก app-server-02<br>Tier 2]
A1 -->|hard| DB[๐ด db-primary-01<br>Tier 1 CRITICAL]
A2 -->|hard| DB
A1 -->|hard| AUTH[๐ด auth-server-01<br>Tier 1 CRITICAL]
A2 -->|hard| AUTH
DB -->|hard| REP[๐ด db-replica-01<br>Tier 1]
style DB fill:#dc3545,color:white
style AUTH fill:#dc3545,color:white
style REP fill:#dc3545,color:white
style LB fill:#0d6efd,color:white
style W1 fill:#ffc107,color:black
style W2 fill:#ffc107,color:black
style A1 fill:#ffc107,color:black
style A2 fill:#ffc107,color:blackโ ๏ธ If DB-Primary goes OFFLINE โ App servers CRASH โ Web servers CASCADE CRASH
๐ CVSS-Driven Risk Scoring
Vulnerabilities are modeled with real-world severity metrics:
- CVSS 9.0-10.0 (CRITICAL): Remote code execution, zero-click exploits
- CVSS 7.0-8.9 (HIGH): Privilege escalation, data exfiltration
- CVSS 4.0-6.9 (MEDIUM): DoS, information disclosure
- Exploit in Wild: 2x penalty multiplier for actively exploited CVEs
๐ฆ Exploit Spreading (Advanced Mechanic)
In incident_response and hard modes, exploited CVEs that remain unpatched on ONLINE nodes for 4+ turns spread to connected nodes via the dependency graph. This creates urgency and rewards proactive patching.
๐ฃ Dynamic Zero-Day Injection (Advanced Mechanic)
In zero_day mode, new CVEs are injected mid-episode:
- Turn 5: CRITICAL zero-day (CVSS 9.9, actively exploited)
- Turn 15: HIGH severity CVE (CVSS 8.4)
The agent must dynamically adapt its strategy when new threats emerge.
๐ฎ Dense Reward Shaping
Unlike sparse-reward environments, PatchCascade provides continuous feedback:
Reward = (Previous Penalty) - (Current Penalty) - 0.1
Where Penalty = Risk_Penalty + Downtime_Penalty
The -0.1 time pressure ensures every step has non-zero reward.๐ Mathematical Formulation
State Space
The environment state at turn t is defined as:
S_t = (N, V_t, D, H_t)
N = {n_i} โ Set of server nodes with (hostname, tier, state, services)
V_t = {v_j} โ Set of active vulnerabilities at turn t
D = {d_k} โ Dependency graph edges (immutable)
H_t โ Aggregate health metrics at turn tReward Function
The reward at each step uses potential-based reward shaping:
R_t = ฮฆ(S_{t-1}) - ฮฆ(S_t) - 0.1 + R_terminal
Where:
ฮฆ(S) = Risk_Penalty(S) + Downtime_Penalty(S)
Risk_Penalty = ฮฃ_j [ cvss_j ร |affected_online_j| ร (2 if exploit_in_wild_j else 1) ]
Downtime_Penalty = ฮฃ_i [ tier_mult(n_i) ร (2 if crashed(n_i) else 1) ] โ n_i โ ONLINE
-0.1 = time pressure penalty (ensures dense non-zero reward every step)
R_terminal = { +50 if all vulns patched, -100 if all nodes crashed, 0 otherwise }This formulation guarantees that every step produces non-zero reward, providing truly dense learning signal throughout the episode.
Normalization
Final scores are normalized to [0, 1] for comparability:
Score = clamp((ฮฃ R_t - R_min) / (R_max - R_min), 0.001, 0.999)
Where R_min = -300.0, R_max = 50.0๐ฎ The Challenge: 5-Level Task Curriculum
PatchCascade offers five progressive difficulty levels, each building on the skills learned in previous levels:
graph LR
E["๐ข Easy<br>Basic Patching"] --> M["๐ก Medium<br>Dependencies"]
M --> H["๐ด Hard<br>Complex Graph"]
H --> IR["๐ฃ Incident Response<br>Active Breach"]
IR --> ZD["โซ Zero-Day<br>Dynamic Threats"]
style E fill:#198754,color:white
style M fill:#ffc107,color:black
style H fill:#dc3545,color:white
style IR fill:#6f42c1,color:white
style ZD fill:#212529,color:white๐ข Level 1: Easy Mode
"Learn the basics"
๐ก Level 2: Medium Mode
"Handle dependencies"
๐ด Level 3: Hard Mode
"Survive the chaos"
๐ฃ Level 4: Incident Response (New!)
"Triage an active breach"
โซ Level 5: Zero-Day Cascade (New!)
"Adapt or die"
๐ Multi-Dimensional Grading
Unlike simple pass/fail or single-metric grading, PatchCascade evaluates agents across four orthogonal dimensions:
graph TB
subgraph "Composite Score (0.0 - 1.0)"
C["๐ Completion (40%)<br>Were all vulns patched?"]
E["โก Efficiency (20%)<br>Steps vs. optimal?"]
S["๐ก๏ธ Safety (20%)<br>Cascades avoided?"]
ST["๐ง Strategy (20%)<br>Smart decisions?"]
end
C --> F["Final Score = ฮฃ w_i ร d_i"]
E --> F
S --> F
ST --> F
style C fill:#198754,color:white
style E fill:#0d6efd,color:white
style S fill:#dc3545,color:white
style ST fill:#6f42c1,color:white
style F fill:#ffc107,color:blackNote: Weights vary by task type. Incident Response uses safety-focused weights (35% safety), while Zero-Day uses efficiency-focused weights (30% efficiency).
Scoring Examples
๐๏ธ Architecture
graph TB
subgraph "PatchCascade SOC Stack"
INF["inference.py<br>๐ค LLM Agent"] --> CLI["client.py<br>๐ก HTTP Client"]
CLI --> SRV["server.py<br>๐ FastAPI"]
SRV --> ENV["environment.py<br>โ๏ธ Core Logic"]
ENV --> MOD["models.py<br>๐ฆ Pydantic Schemas"]
SRV --> GRD["grader.py<br>๐ Multi-Dim Grading"]
SRV --> TSK["tasks/<br>๐ 5 Task Definitions"]
end
style INF fill:#0d6efd,color:white
style CLI fill:#198754,color:white
style SRV fill:#dc3545,color:white
style ENV fill:#ffc107,color:black
style MOD fill:#6f42c1,color:white
style GRD fill:#fd7e14,color:white
style TSK fill:#20c997,color:white๐ Quick Start
Option 1: Docker (Recommended)
# Build the container
docker build -t patchcascade-soc .
# Run the server
docker run -p 8000:8000 patchcascade-soc
# Test the endpoint
curl -X POST http://localhost:8000/reset \
-H "Content-Type: application/json" \
-d '{"task_level": "medium"}'Option 2: Local Development
# Install dependencies
pip install -r requirements.txt
# Start the server
uvicorn server:app --host 0.0.0.0 --port 8000 --reload
# Run the baseline agent
export HF_TOKEN="your_huggingface_token"
export MODEL_NAME="Qwen/Qwen2.5-72B-Instruct"
python inference.pyValidate Your Submission
bash validate-submission.sh https://your-space.hf.space๐ฌ Sample Interaction
from client import PatchCascadeLocalClient, PatchCascadeAction
# Initialize local client (no server needed)
client = PatchCascadeLocalClient()
# Try the new Incident Response mode!
obs = client.reset(task_level="incident_response")
print(f"Nodes: {[n.hostname for n in obs.nodes]}")
print(f"Crashed: {[n.hostname for n in obs.nodes if n.state == 'crashed']}")
print(f"Vulns: {[v.cve_id for v in obs.vulnerabilities]}")
print(f"Messages: {obs.messages}")
# Output: "โ ๏ธ ACTIVE BREACH: Multiple nodes are already compromised..."
# Recover a crashed node first
from models import ActionType
action = PatchCascadeAction(
action_type=ActionType.RESUME_SERVICE,
target="db-primary-01",
reason="Recover crashed database to restore app layer"
)
result = client.step(action)
print(f"Reward: {result.reward:.2f}, Done: {result.done}")๐ฅ๏ธ Rich ASCII Visualization
The environment provides a beautiful ASCII network diagram for debugging:
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ ๐ก๏ธ PatchCascade SOC โ Turn 5/50 (Incident Response) โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฃ
โ NETWORK TOPOLOGY โ
โ โ
โ ๐ข db-primary-0 [ ONLINE ] T1 โ ๏ธ ๐ด app-server-0 [CRASHED ] T2 ๐ฅโ
โ ๐ข web-frontend [ ONLINE ] T2 โ ๏ธ ๐ก cache-redis- [SUSPENDED] T3 โ
โ ๐ต auth-server- [PATCHING] T2 ๐ข api-gateway [ ONLINE ] T2 โ
โ โ
โ DEPENDENCIES โ
โ web-fronte โโโบ app-server โ
โ app-server โโโบ db-primary โ
โ auth-serve โโโบ db-primary โ
โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฃ
โ VULNS: 3 active (1 CRIT, 2 HIGH) (1 exploited!) โ
โ HEALTH: 4/6 online | 1 crashed | Risk: 12.5 | Downtime: 8.0 โ
โ REWARD: +15.50 (last: +3.20) โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโLegend: ๐ข Online | ๐ด Crashed | ๐ก Suspended | ๐ต Patching | โ ๏ธ Has vulnerability | ๐ฅ Exploited
๐ฏ Example: Optimal Agent Strategy (Medium Mode)
Here's a step-by-step walkthrough of an optimal agent solving the medium task:
Turn 0: Observe โ 6 nodes, 2 CVEs (db-primary-01 has CVE-2024-2001, web frontends have CVE-2024-2002)
Dependencies: web โ app โ db-primary-01
Turn 1: suspend_service(web-frontend-01) โ Protect from cascade
Turn 2: suspend_service(web-frontend-02) โ Protect from cascade
Turn 3: suspend_service(app-server-01) โ Protect from cascade
Turn 4: suspend_service(app-server-02) โ Protect from cascade
Turn 5: suspend_service(db-primary-01) โ Required: Tier 1 must be SUSPENDED
Turn 6: apply_patch(db-primary-01, CVE-2024-2001) โ Patch critical DB vuln
[Patch completes next turn โ db-primary-01 returns to ONLINE]
Turn 7: resume_service(app-server-01) โ DB is online, safe to resume
Turn 8: resume_service(app-server-02) โ Resume second app server
Turn 9: resume_service(web-frontend-01) โ Resume web (still has CVE-2024-2002)
Turn 10: apply_patch(web-frontend-01, CVE-2024-2002) โ Patch web vuln
Turn 11: resume_service(web-frontend-02)
Turn 12: apply_patch(web-frontend-02, CVE-2024-2002) โ Patch second web server
Result: All patched in 12 steps, 0 cascade failures, 0 invalid actions
Score: completion=1.0, efficiency=0.85, safety=1.0, strategy=1.0 โ Final: 0.95๐ก API Reference
POST /reset
Initialize a new episode.
// Request
{ "task_level": "incident_response", "seed": 42 }
// Response
{ "observation": { "nodes": [...], "vulnerabilities": [...], ... } }POST /step
Execute an action.
// Request
{
"action_type": "apply_patch",
"target": "web-frontend-01",
"cve_id": "CVE-2024-1234"
}
// Response
{
"observation": { ... },
"reward": 7.5,
"done": false,
"truncated": false,
"info": { "valid": true, "cascade_failures": 0, "total_cascade_failures": 0 }
}GET /tasks
List all 5 tasks with grader information.
POST /grade/{task_id}
Grade an episode using multi-dimensional programmatic grading.
GET /metadata
Get full environment metadata including all tasks, graders, and schemas.
Action Types
๐ง Agent Strategy Tips
- Suspend dependents first: Before patching a Tier 1 node, suspend all nodes that depend on it
- Prioritize exploited CVEs:
exploit_in_wild=truemeans 2x risk penalty per turn โ and in advanced modes, they spread to connected nodes - Batch patches efficiently: While one node is PATCHING, work on independent branches
- Don't fear downtime: A controlled SUSPENDED state is better than an uncontrolled CRASH
- Watch for dynamic events: In zero-day mode, new CVEs appear at turns 5 and 15 โ be ready to reprioritize
- Recover before patching: In incident response mode, crashed nodes must be resumed before they can be patched
๐ Evaluation Metrics
๐ Agent Benchmark Results
We evaluate four agent types across all five task levels using our multi-dimensional grading system. Scores are composite (Completion ร Efficiency ร Safety ร Strategy), normalized to [0.0, 1.0].
Run python benchmark.py --episodes 10 to reproduce these results.Note: RL training uses PPO via Stable-Baselines3 with our Gymnasium wrapper. See `train_rl.py` for training scripts and hyperparameters.
๐๏ธ Train Your Own Agent
PatchCascade includes a Gymnasium-compatible wrapper for seamless integration with standard RL libraries:
# Quick training with Stable-Baselines3
from gym_wrapper import PatchCascadeGymEnv
from stable_baselines3 import PPO
env = PatchCascadeGymEnv(task_level="medium")
model = PPO("MlpPolicy", env, verbose=1)
model.learn(total_timesteps=50_000)# CLI training (all levels, curriculum learning, plotting)
python train_rl.py --task easy --steps 10000 # Quick test
python train_rl.py --all --steps 50000 # Train all levels
python train_rl.py --curriculum # Curriculum: easyโmediumโhard
python train_rl.py --plot # Generate training curves
python benchmark.py --episodes 20 # Full benchmark suite๐ License
Apache 2.0 โ See LICENSE for details.
๐ฅ Contributors
<table> <tr> <td align="center"> <a href="https://github.com/Ayush-Kumar0207"> <img src="https://github.com/Ayush-Kumar0207.png" width="100px;" alt="Ayush Kumar"/><br/> <sub><b>Ayush Kumar</b></sub> </a><br/> <sub>๐ Team Lead | Core Builder</sub> </td> <td align="center"> <a href="https://github.com/cypher00grd"> <img src="https://github.com/cypher00grd.png" width="100px;" alt="Ravi Prashant"/><br/> <sub><b>Ravi Prashant</b></sub> </a><br/> <sub>๐๏ธ Architect and Developer</sub> </td> </tr> </table>
๐ ๏ธ Built With
๐ Acknowledgments
- Meta AI โ For hosting the PyTorch OpenEnv Hackathon
- Hugging Face โ For Spaces infrastructure
- OpenEnv Community โ For the standardized RL environment protocol
<div align="center">
Built for the Meta PyTorch OpenEnv Hackathon 2026
Created by Ayush Kumar & Ravi Prashant
Train smarter. Patch faster. Crash never.
Made with โค๏ธ in India
</div>
