Skip to content

DenSecMan/MySec

Repository files navigation

MySec

A personal, CLI-based SOC investigation assistant for Microsoft Azure Sentinel. MySec uses a LangGraph multi-agent system backed by Azure OpenAI to let you investigate incidents, enrich entities, and query Sentinel data through a natural-language conversation — no portal pivoting, no manual KQL.


Overview

MySec runs as a full-screen terminal application. The supervisor agent ("MySec") directly investigates incidents end-to-end — pulling incidents, extracting entities, dispatching to specialist agents, following new leads, and synthesising everything into a consolidated markdown report.

MySec > investigate incident 1234

MySec will automatically:

  1. Pull the incident from SecurityIncident and all linked alerts from SecurityAlert
  2. Extract typed entities (IPs, user accounts, hostnames, URLs, file hashes) from alert evidence
  3. State an investigation plan based on incident type, severity, and discovered entities
  4. Dispatch each entity type to the appropriate specialist agent
  5. Analyse returned data, follow any new leads with further agent calls
  6. Return a full consolidated investigation summary

Agents

Agent Role Data Sources
MySec (Supervisor) Incident triage, investigation coordination, synthesis SecurityIncident, SecurityAlert + all specialist agents
Threat IOC enrichment — IPs, domains, URLs, file hashes VirusTotal, AbuseIPDB, AlienVault OTX
Identity User activity — sign-ins, audit events, risk data SigninLogs, AuditLogs, AADRiskyUsers, AADUserRiskEvents
Endpoint Device activity — processes, logons, network, files DeviceProcessEvents, DeviceLogonEvents, DeviceNetworkEvents, DeviceFileEvents
Network Traffic, DNS, firewall activity CommonSecurityLog, HUNT_Bluecat, AzureNetworkAnalytics_CL
Office Microsoft 365 activity — SharePoint, Exchange, Teams OfficeActivity, CloudAppEvents
Web Internet proxy activity via Zscaler HUNT_Zscaler
Azure Azure control-plane and resource diagnostic activity AzureActivity, AzureDiagnostics, StorageBlobLogs
KQL Natural-language to KQL — executes ad-hoc queries and self-corrects on errors Any Log Analytics table
Hunter Proactive threat hunting — hypothesis-driven, MITRE ATT&CK aligned, writes hunt reports All workspace tables
NVD-CVE CVE research — CVSS scoring, exploitability assessment, patch prioritisation LLM knowledge + nvd-cve skill
Qualys Qualys vulnerability inventory for a specific host QualysHostDetectionV3_CL

All specialist agents are goal-driven and run autonomously until their goal is satisfied, all tools have exhausted retries, or a configurable max-iteration cap is hit.

Data source note — HUNT_ tables: Tables prefixed HUNT_ are Azure Data Explorer (ADX) tables accessed through the Sentinel API as workspace functions, not native Log Analytics tables. Some require function-call syntax (HUNT_Bluecat(), HUNT_Zscaler()); all require column_ifexists() guards since their column schemas vary by workspace.


Requirements

  • Python 3.11+
  • Azure OpenAI deployment
  • Azure Log Analytics workspace (Sentinel)
  • Azure Service Principal with Log Analytics Reader on the workspace
  • API keys for VirusTotal, AbuseIPDB, and AlienVault OTX (optional — agents degrade gracefully if absent)

Setup

1. Clone and create a virtual environment

git clone <repo-url>
cd MySec
python -m venv .venv
.venv\Scripts\activate   # Windows
# source .venv/bin/activate  # macOS/Linux
pip install -r requirements.txt

2. Configure environment variables

Copy .env.example to .env and fill in your values (never commit the populated file):

# Azure OpenAI
AZURE_OPENAI_API_KEY=
AZURE_OPENAI_ENDPOINT=
AZURE_OPENAI_DEPLOYMENT=
AZURE_OPENAI_API_VERSION=2024-02-01

# Azure Service Principal (Log Analytics Reader on the Sentinel workspace)
AZURE_TENANT_ID=
AZURE_CLIENT_ID=
AZURE_CLIENT_SECRET=
AZURE_WORKSPACE_ID=

# Threat Intelligence (optional — agents note when keys are absent)
VIRUSTOTAL_API_KEY=
ABUSEIPDB_API_KEY=
ALIENVAULT_OTX_API_KEY=

3. Review global settings

Edit config/app.yaml to adjust defaults:

lookback_days: 30       # KQL lookback window
row_limit: 500          # Max rows per query
max_retries: 3          # Retries on transient API errors
log_level: INFO         # DEBUG for full LLM/tool traces

4. Run

# Interactive TUI
python main.py

# Single-shot investigation (exits after response)
python main.py investigate 1234

Usage

Interactive mode

Running python main.py without arguments launches the full-screen Textual TUI — a two-panel layout with the conversation on the left and a live agent/tool status panel on the right.

Type any natural-language request in the input box and press Enter. Example prompts:

investigate incident 1234
what did user john.doe@contoso.com do in the last 7 days?
get threat intel for 185.220.101.45
show me Azure activity for resource group rg-production
what web sites did jane.smith@contoso.com visit yesterday?
hunt for password spray activity over the last 7 days
show me all failed sign-ins from outside Australia in the last 24 hours
research CVE-2024-21413 with nvd-cve
get the Qualys vulnerability report for host WIN-PROD-01
Key Action
Enter Submit prompt
/ Open command menu
/ (command menu open) Navigate command suggestions
/ (command menu closed) Recall previous / next submitted input (history navigation)
Escape Close command menu
Ctrl+L Clear conversation log
Ctrl+C Quit

Single-shot mode

python main.py investigate 1234
python main.py what did user john.doe@contoso.com do in the last 7 days

Prints the response and exits. The report is saved to reports/.


Commands

Type / in the input box to open a searchable command menu. Arrow keys navigate the list; Enter selects.

Listing

Command Description
/ListAgents Display all registered agents with their tools and purpose
/ListTools Display all tool modules and the @tool functions they export
/ListSkills Display all available skills with name, description, and tags

Scaffolding — create new components

Command Description
/NewAgent <goal description> Have the supervisor create a new sub-agent, its companion skill, register it, and hot-reload
/NewTool <goal description> Have the supervisor create a new tool module and wire it to agents
/NewSkill <goal description> Have the supervisor create a new skill

The supervisor follows a strict 8-step workflow (defined in skills/scaffold/SKILL.md) including mandatory validation before hot-reload. New components are live immediately — no restart required.

Scaffolding — remove components

Command Description
/RemoveAgent <name> Remove an agent directory, deregister it, and strip it from all agent configs
/RemoveTool <name> Remove a tool module and strip its functions from all agent configs
/RemoveSkill <name> Remove a skill directory

Verification

Command Description
/verify agent <name> Health-check an agent — structure, config, tool resolution, skill, registry, import
/verify skill <name> Health-check a skill — frontmatter, body, skill_store availability
/verify tool <name> Health-check a tool module — import, docstrings, credential pattern, agent wiring
/verify agent all Health-check every registered agent, summary table
/verify skill all Health-check every skill in skills/, summary table
/verify tool all Health-check every tool module in tools/, summary table
/verify all Health-check all agents, skills, and tools in one summary table

Each check reports ✓ Pass or ✗ Fail with a concrete fix instruction. The bulk "all" commands show one row per component; components with errors are listed at the bottom with the exact individual command to see full details.

Other

Command Description
/clear Clear the conversation log and reset conversation history
/help Show all available commands
/quit Exit MySec

Scaffold System

MySec includes a built-in scaffolding system that lets the supervisor create, validate, wire, and hot-reload new agents, tools, and skills without any manual file editing or restarts.

How it works

  1. The user issues /NewAgent <goal> in the TUI.
  2. The TUI dispatches a structured prompt to the supervisor.
  3. The supervisor calls scaffold tools in order:
    • scaffold_read_template("agent") — reads the canonical template
    • scaffold_write_skill(name, content) — creates the companion skill first
    • scaffold_write_agent(name, agent_py, config_yaml) — writes both files
    • scaffold_validate_agent(name)mandatory structural check before proceeding
    • scaffold_register_agent(name) — adds to agents/_registry.py
    • scaffold_update_agent_config(...) — wires to any other agents the user specifies
    • scaffold_hotreload(summary) — triggers live reload; new agent is available immediately

Validation

scaffold_validate_agent catches every known failure mode before hot-reload:

Check What it prevents
@tool decorator present Class-based implementations
async def <name>_agent exact match Wrong function name, missing _agent suffix
load_agent_config / resolve_tools / create_react_agent present Incomplete template use
No class definitions Object-oriented misuse of the template
system_prompt non-empty and calls load_skill() Agents that ignore their domain knowledge
config.yaml has name, max_iterations, tools Missing required config fields
skills/<name>/SKILL.md exists Missing companion skill
SKILL.md has opening and closing --- Broken frontmatter that prevents skill loading

If validation fails, the supervisor rewrites the affected file and retries — scaffold_hotreload is never called until scaffold_validate_agent returns valid: true.

Security scope

Scaffold tools enforce strict path guards:

  • Writes are only permitted inside agents/, tools/, and skills/
  • agents/mysec/ (the supervisor) is write-protected
  • Template directories are write-protected
  • scaffold_tools.py and skill_tools.py cannot be modified by the scaffold system
  • Credentials are always read from .env — the supervisor never generates or hardcodes values

Hot-reload

After any scaffold write operation, the TUI automatically:

  1. Re-scans all tools/*.py modules and rebuilds the tool registry
  2. Re-scans skills/ and reinitialises the skill store
  3. Reloads agents/_registry.py and re-imports all registered agents
  4. Rebuilds the supervisor with the updated tool and agent lists

No restart is required. The ↺ System reloaded message confirms the reload completed.


Project Structure

MySec/
├── main.py                    # Entry point — CLI args, TUI launch, single-shot mode
├── config/
│   └── app.yaml               # Global settings (lookback_days, row_limit, log_level, etc.)
├── agents/
│   ├── _registry.py           # COMMITTED — list of registered agent names (dynamic loader)
│   ├── _template/             # COMMITTED — boilerplate for creating new agents
│   │   ├── agent.py
│   │   └── config.yaml
│   ├── mysec/                 # local only — supervisor
│   ├── threat/                # local only — Threat Intelligence
│   ├── identity/              # local only — Identity Investigation
│   ├── endpoint/              # local only — Endpoint Investigation
│   ├── network/               # local only — Network Investigation
│   ├── office/                # local only — Office 365 Investigation
│   ├── web/                   # local only — Web Proxy Investigation
│   ├── azure/                 # local only — Azure Resource Investigation
│   ├── kql/                   # local only — Ad-hoc KQL
│   ├── hunter/                # local only — Proactive threat hunting
│   ├── nvd-cve/          # local only — CVE / vulnerability research
│   └── qualys/  # local only — Qualys endpoint vulnerability report
├── tools/
│   ├── _template_tools.py     # COMMITTED — boilerplate for creating new tools
│   ├── skill_tools.py         # COMMITTED — list_skills, load_skill (skill infrastructure)
│   ├── scaffold_tools.py      # local only — scaffold system tools (write/validate/remove/reload)
│   └── *.py                   # local only — workspace-specific tool implementations
├── core/
│   ├── log_analytics.py       # Async KQL client (service principal auth, retry)
│   ├── llm.py                 # AzureChatOpenAI factory
│   ├── config_loader.py       # YAML config loader and validation
│   ├── tool_loader.py         # Dynamic tool registry — scans tools/*.py at startup and on reload
│   ├── skill_store.py         # SkillStore — scans skills/, serves content on demand
│   ├── callbacks.py           # AgentTraceCallback — logs prompts, tool calls, tool results
│   ├── tui.py                 # Textual TUI — MySecApp, AgentPanel, command handling
│   ├── status_panel.py        # Rich Live status panel (single-shot mode)
│   ├── memory.py              # Self-learning KQL pattern store
│   ├── report.py              # Session report writer
│   ├── console.py             # Shared Rich Console and severity colour helpers
│   ├── state.py               # LangGraph TypedDict state
│   └── agent_loop.py          # Goal-driven loop helper
├── skills/                    # Agent skill library — domain knowledge loaded on demand
│   ├── _template/             # COMMITTED — boilerplate for creating new skills
│   │   └── SKILL.md
│   ├── scaffold/              # local only — scaffold workflow guide (used by supervisor)
│   └── */SKILL.md             # local only — workspace-specific domain knowledge
├── logs/
│   ├── app.log                # JSON structured log (cleared on startup)
│   └── conversation.log       # Human-readable transcript (cleared on startup)
├── memory/
│   └── patterns.json          # Self-learning KQL pattern store (auto-created)
├── reports/                   # Investigation reports — one .md per run, kept permanently
├── scripts/
│   └── sync_gitignore.py      # Toggles gitignore exclusions based on commit_implementations
└── .env                       # Secrets — never commit

Skills System

MySec uses a lazy-loading skill system to keep LLM context lean. Domain knowledge — detection thresholds, indicator lists, KQL templates, schema references — lives in skills/<name>/SKILL.md files and is loaded only when an agent determines it is relevant.

Every agent has two skill tools available:

Tool Description
list_skills(query) Returns skill names and one-line descriptions. Lightweight — no full content.
load_skill(name) Returns the full SKILL.md content for a specific skill.

Each SKILL.md has YAML frontmatter (between --- delimiters) and a markdown body:

---
name: identity-anomaly-detection
description: Azure AD anomaly detection criteria, thresholds, and risk indicators
tags:
  - identity
  - azure-ad
---

# Identity Anomaly Detection
...full knowledge content...

Available Skills

Skill Purpose
identity-anomaly-detection Azure AD sign-in anomaly criteria, MFA codes, risk event types
endpoint-indicators LOLBin list, suspicious process patterns, lateral movement indicators
network-analysis RFC1918 classification, traffic summary fields, DNS tunneling indicators
office365-risk-indicators High-risk O365 operation types, bulk download thresholds
azure-risk-operations High-risk ARM operations, Key Vault access patterns, anti-forensics indicators
threat-intel-verdict IOC verdict synthesis rules, source weighting, per-IOC report format
sentinel-schema All Sentinel table schemas and key columns
kql-techniques KQL idioms, column safety, self-correction patterns
nvd-cve CVSS v3.1 scoring, severity bands, exploitability flags, vulnerability types, report format (used by nvd-cve agent)
qualys QualysHostDetectionV3_CL schema, KQL templates, severity thresholds, output format (used by qualys agent)
scaffold Step-by-step workflow for creating and removing agents, tools, and skills (used by supervisor)
hunt-credential-access Credential access KQL templates (T1078, T1110, T1556)
hunt-persistence Persistence KQL templates (T1098, T1136, T1137, T1053)
hunt-lateral-movement Lateral movement KQL templates (T1021, T1550, T1570)
hunt-execution Execution KQL templates (T1059, T1047, T1218)
hunt-defense-evasion Defense evasion KQL templates (T1562, T1070)
hunt-command-and-control C2 KQL templates (T1071, T1568, T1571)
hunt-exfiltration Exfiltration KQL templates (T1567, T1048, T1537)
hunt-discovery Discovery KQL templates (T1087, T1526)
hunt-initial-access Initial access KQL templates (T1566, T1133)
hunt-outcome-criteria Campaign outcome criteria (No / Emerging / Full Campaign)
hunt-data-sources Available Sentinel tables for hunting, workspace naming conventions

Dynamic Agent Registry

Agents are discovered at startup and on every hot-reload via agents/_registry.py:

AGENTS = [
    "threat", "identity", "endpoint", "network",
    "office", "web", "azure", "kql", "hunter",
    "nvd-cve", "qualys",
]

Each name must match the directory under agents/ and the exported @tool function (<name>_agent, with hyphens converted to underscores). The supervisor receives all registered agents as tools automatically — no changes to agents/mysec/ are needed when adding a new agent.

Agents with hyphenated directory names (e.g. qualys) are loaded via file-path import and mapped to the underscore function name (endpoint_vuln_report_agent).


Dynamic Tool Registry

core/tool_loader.py scans all tools/*.py files at startup (and after every hot-reload), importing each module and collecting BaseTool instances. Agent config.yaml files list tool names instead of imports:

tools:
  - execute_kql
  - get_kql_patterns
  - list_skills
  - load_skill

resolve_tools(config.tools) is called inside every agent's ainvoke loop — new tool files are picked up without any import changes in agent.py.


Agent Configuration

Each agent's behaviour is controlled entirely by its config.yaml. System prompts contain only workflow steps and rules — all domain knowledge is in skills, loaded on demand.

name: identity
max_iterations: 10
tools:
  - get_signin_logs
  - get_noninteractive_signins
  - get_audit_logs
  - get_risky_users
  - get_user_risk_events
  - list_skills
  - load_skill
system_prompt: |
  You are the Identity Investigation agent...
  Before analysing results, call load_skill("identity-anomaly-detection")...

Edit system_prompt to tune analysis behaviour. Edit or add SKILL.md files to update domain knowledge — no agent code changes required.


Threat Hunting

The Hunter agent performs hypothesis-driven threat hunts against Sentinel data, aligned to MITRE ATT&CK. Invoke it via any natural-language hunt request:

hunt for credential access activity over the last 7 days
hunt for lateral movement using T1021
look for living-off-the-land techniques on endpoints this week

The Hunter agent will:

  1. Clarify the hypothesis and map it to MITRE ATT&CK techniques
  2. Call list_skills(query="hunt") to discover available hunt template skills
  3. Load the relevant skill for KQL templates
  4. Check memory for prior working queries on each table
  5. Execute queries, self-correcting on column or syntax errors (up to 5 attempts per query)
  6. Assess evidence against three outcomes: No Campaign, Emerging Campaign, or Full Campaign Identified
  7. Write a structured hunt report to reports/
  8. Return a concise summary with findings, IOCs, and recommended actions

Zero-result queries are still reported — they confirm coverage, not absence of a hunt.


Ad-hoc KQL

The KQL agent converts any natural-language data request into a KQL query, executes it, and returns formatted results. It self-corrects on errors (wrong column names, absent tables, timeouts) for up to five attempts.

show all sign-ins from IP 185.220.101.45 in the last 30 days
how many failed authentications per user in the last 7 days?
list all Key Vault access events for vault kv-prod yesterday

Results include the row count, time range, and the final KQL query for reuse.


Vulnerability Research

The NVD-CVE agent researches CVEs referenced in incidents or requested directly:

research CVE-2024-21413
what is the severity of the PrintNightmare vulnerability?
is there an active exploit for CVE-2023-44487?

The agent returns a structured report covering CVSS v3.1 score and vector, exploitability (public exploit, CISA KEV status, active exploitation), affected products, patch SLA based on severity, and remediation guidance.

The Qualys agent queries Qualys scan data from QualysHostDetectionV3_CL:

get the vulnerability report for 10.1.2.3
show me all critical vulnerabilities on host WIN-PROD-01

Returns a summary of vulnerabilities by severity band, with long-standing open issues (open > 30 days) flagged for escalation.


Self-Learning

After each session, MySec writes successful KQL queries (those that returned >0 rows) to memory/patterns.json. On subsequent runs, agents consult this store to prefer query patterns that have worked before for the same table and entity type.

memory/patterns.json is plain JSON and fully editable — delete stale entries directly if needed.


Logs and Reports

File Contents Cleared on startup
logs/app.log JSON structured log — agent invocations, tool calls, LLM requests, errors Yes
logs/conversation.log Plain-text transcript of the full analyst ↔ MySec conversation Yes
reports/<timestamp>_investigation.md Markdown report of the session — one file per run, kept permanently No

Creating New Components

Use the TUI slash commands — the scaffold system handles all file creation, wiring, validation, and hot-reload automatically.

/NewAgent <goal>

The supervisor will:

  1. Read the agent template and scaffold skill
  2. Create a companion skill with domain knowledge, KQL templates, and output format
  3. Write agents/<name>/agent.py and config.yaml from the template
  4. Run scaffold_validate_agent — fix and retry until all checks pass
  5. Register the agent in _registry.py
  6. Ask which specialist agents should be able to call this new agent
  7. Hot-reload — the agent is live immediately

/NewTool <goal>

The supervisor will create tools/<name>_tools.py, wire the tool names into the relevant agent configs, and hot-reload.

/NewSkill <goal>

The supervisor will create skills/<name>/SKILL.md with proper frontmatter and domain content.

Manual creation (advanced)

If creating components outside the TUI, follow the templates in agents/_template/, tools/_template_tools.py, and skills/_template/SKILL.md. Run /verify agent|skill|tool <name> after creation to confirm correctness.


Git Scope

By default only templates and shared infrastructure are committed. The commit_implementations flag in config/app.yaml controls whether agent, skill, and tool implementations are also tracked.

# false (default) — only templates committed; implementations are gitignored
# true            — agents/, skills/, tools/ implementations are tracked
commit_implementations: false

Apply the change after editing:

python scripts/sync_gitignore.py

Default scope

Path Default Reason
agents/_registry.py Committed Agent discovery list
agents/_template/ Committed Boilerplate for new agents
agents/*/ (all others) Gitignored Workspace-specific
tools/_template_tools.py Committed Boilerplate for new tool modules
tools/skill_tools.py Committed Skill system infrastructure
tools/*.py (all others) Gitignored Workspace-specific
skills/_template/ Committed Boilerplate for new skills
skills/*/ (all others) Gitignored Workspace-specific
core/tool_loader.py Committed Dynamic tool registry
logs/, reports/, memory/ Always gitignored Runtime output — may contain incident / PII data
.env Always gitignored Secrets — never commit

Security Notes

  • All credentials are read from environment variables — never hard-coded.
  • All user-supplied values (incident IDs, UPNs, IPs) are sanitised before inclusion in KQL strings.
  • Log Analytics queries go through the azure-monitor-query SDK with service principal auth.
  • Scaffold tools enforce write restrictions — only agents/, tools/, and skills/ are writable; the supervisor agent and all templates are protected.
  • .gitignore excludes all secrets, runtime output, and workspace-specific implementations by default.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages