This document covers the threat model, hardening recommendations, and security architecture for E8CR Squad deployments.
Each E8CR bot is an autonomous OpenClaw agent with read access to your Microsoft 365 tenant via the Microsoft Graph API. By default, all bots operate in audit-only mode (E8CR_ENABLE_CHANGES=false).
If an attacker gains control of an E8CR bot instance:
| Scenario | Blast radius | Mitigation |
|---|---|---|
| Attacker reads Graph API data | Visibility into device inventory, user list, MFA status, CA policies, patch compliance, backup job status. No access to email, files, or passwords. | Use least-privilege permissions (read-only scopes). See Graph API Permissions. |
| Attacker modifies bot SOUL/AGENTS files | Bot could produce misleading compliance reports (false "healthy" status). No write access to tenant unless E8CR_ENABLE_CHANGES=true. |
File integrity monitoring. Store SOUL/AGENTS files in version control. Separate the signing key from the bot host. |
| Attacker accesses signing key | Could forge evidence manifests that appear authentic. | Store E8CR_SIGNING_KEY separately from bot hosts. Rotate after any suspected compromise. Use hardware-backed secrets management if available. |
| Attacker accesses Azure credentials | Full access to whatever Graph API scopes are granted to that app registration. | One app registration per bot with minimal scopes. Rotate client secrets regularly. Use certificate-based auth where possible. |
| Attacker pivots to tenant (write mode enabled) | Could deploy patches, modify policies, change configurations. | Keep E8CR_ENABLE_CHANGES=false unless actively deploying changes. Use separate app registrations for read vs write operations. |
Each bot runs as a separate OpenClaw instance with its own:
- Azure AD app registration (separate client ID and secret)
- Graph API permissions (only what that bot needs)
- Memory and state (no cross-bot data sharing at runtime)
- Process isolation (separate container/VM/service)
If the Identity bot is compromised, the attacker has no access to vulnerability data, backup configurations, or application control policies.
Each bot should have its own Azure AD app registration with only the permissions it requires. All permissions below are Application type (not Delegated).
| Permission | Why needed | What to avoid |
|---|---|---|
DeviceManagementManagedDevices.Read.All |
Read device inventory and compliance state | .ReadWrite.All — no need to modify devices |
DeviceManagementConfiguration.Read.All |
Read update ring assignments and compliance policies | .ReadWrite.All |
WindowsUpdates.Read.All |
Read Windows Update for Business deployment state | .ReadWrite.All |
If using Microsoft Defender Vulnerability Management (E5/MDE P2):
| Permission | Why needed |
|---|---|
Vulnerability.Read.All |
Read vulnerability assessments |
Software.Read.All |
Read software inventory |
Machine.Read.All |
Read machine details for vulnerability correlation |
| Permission | Why needed | What to avoid |
|---|---|---|
User.Read.All |
Read user profiles, MFA registration status | User.ReadWrite.All |
Directory.Read.All |
Read directory objects, group memberships | Directory.ReadWrite.All |
Policy.Read.All |
Read Conditional Access policies | Policy.ReadWrite.ConditionalAccess |
AuditLog.Read.All |
Read sign-in logs for legacy auth and break-glass detection | — |
RoleManagement.Read.All |
Read admin role assignments | RoleManagement.ReadWrite.Directory |
UserAuthenticationMethod.Read.All |
Read MFA methods per user | .ReadWrite.All |
| Permission | Why needed | What to avoid |
|---|---|---|
DeviceManagementConfiguration.Read.All |
Read WDAC, macro, and hardening policies | .ReadWrite.All |
DeviceManagementManagedDevices.Read.All |
Read device compliance against policies | .ReadWrite.All |
| Permission | Why needed | What to avoid |
|---|---|---|
DeviceManagementManagedDevices.Read.All |
Read device inventory for coverage mapping | .ReadWrite.All |
The Backup bot primarily queries on-premises backup providers (Veeam, Azure Backup) via their own APIs. Graph API access is minimal.
Directory.ReadWrite.All— can modify any directory objectRoleManagement.ReadWrite.Directory— can assign admin rolesApplication.ReadWrite.All— can modify app registrationsMail.Read/Mail.ReadWrite— E8CR never needs email accessFiles.Read.All/Sites.Read.All— E8CR never needs file/SharePoint access
Run each bot in its own container with:
- Read-only filesystem (mount evidence output directory as writable volume)
- No network access except to
graph.microsoft.comand required API endpoints - No inter-container communication
- Resource limits (CPU, memory) to prevent resource exhaustion
- Non-root user
See Docker deployment for a ready-to-use setup.
For higher assurance environments:
- Dedicate one VM per bot
- Use host firewall to restrict outbound to
login.microsoftonline.com,graph.microsoft.com, and backup provider endpoints only - No inbound access required (bots are pull-only)
- Harden the OS (CIS benchmark, unattended updates)
┌─────────────────────────────────────────────────┐
│ Management Network │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ VM+PM │ │ Identity │ │ AppCtrl │ ... │
│ │ Bot │ │ Bot │ │ Bot │ │
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ │
│ │ │ │ │
│ └──────────────┼──────────────┘ │
│ │ │
│ ┌───────▼────────┐ │
│ │ Egress-only │ │
│ │ Firewall │ │
│ └───────┬────────┘ │
└──────────────────────┼──────────────────────────┘
│
graph.microsoft.com
login.microsoftonline.com
- Bots should never be internet-facing
- No inbound ports required
- Egress restricted to Microsoft identity and Graph endpoints
- Evidence output stored on a separate, access-controlled volume
E8CR agents are resilient to prompt injection by design:
-
No user-controlled inputs to tool calls. Bot scripts receive parameters from their
bot.contract.yamlcommand registry and environment variables — never from tenant data or API responses. A malicious device name or user display name in Graph API data cannot influence what scripts the bot runs. -
Separate SOUL/SKILL files. The agent's identity, decision framework, and operational protocols are defined in version-controlled markdown files, not constructed from runtime data. An attacker cannot modify the agent's instructions by manipulating tenant data.
-
Safe-by-default mode. Even if an agent's reasoning were somehow influenced,
E8CR_ENABLE_CHANGES=falseprevents any write actions. The worst case in audit mode is a misleading report — not a tenant modification. -
Structured output parsing. Bot scripts output JSON with defined schemas. The agent validates evidence against JSON schemas (
schemas/*.schema.json) before including it in reports. Malformed data is flagged, not silently accepted. -
No dynamic tool loading. The set of available scripts is fixed per bot. There is no mechanism for an agent to download or execute arbitrary code.
- If
E8CR_ENABLE_CHANGES=trueand an agent's reasoning is compromised, it could theoretically deploy unwanted patches or policy changes. Mitigation: keep write mode disabled except during supervised remediation windows. - Misleading compliance reports could give false assurance. Mitigation: human review of all reports before relying on them for compliance decisions.
The evidence signing system in shared/evidence_pack.py uses HMAC-SHA256 to create tamper-evident evidence manifests.
Signing process:
- All evidence files in the output directory are enumerated
- Each file is hashed with SHA-256
- A manifest is built containing file paths, sizes, and hashes
- The manifest JSON (canonical form: sorted keys, compact separators) is signed with HMAC-SHA256 using
E8CR_SIGNING_KEY - The signature is written to
manifest.sig - The manifest (with signature metadata) is written to
manifest.json
Verification process:
Use the verification CLI to independently check evidence integrity:
# Verify file hashes only (no signing key needed)
python3 scripts/verify_evidence.py /path/to/evidence/manifest.json
# Verify file hashes AND HMAC signature
E8CR_SIGNING_KEY=your-key python3 scripts/verify_evidence.py /path/to/evidence/manifest.json- The signing key (
E8CR_SIGNING_KEY) should be stored separately from the bot hosts - Use a secrets manager (Azure Key Vault, AWS Secrets Manager, HashiCorp Vault) in production
- Rotate the key periodically and after any suspected compromise
- Share the key with assessors through a secure channel for verification
- The key should be at least 32 characters of cryptographically random data
- Integrity: Evidence files have not been modified since the manifest was generated
- Authenticity: Only someone with the signing key could have produced the signature
- Completeness: All files present at signing time are listed in the manifest
- Non-repudiation: HMAC is symmetric — the signer and verifier share the same key. For non-repudiation, consider asymmetric signing (future enhancement).
- Timestamp authenticity: The
generatedAttimestamp is self-reported. For trusted timestamps, use an external timestamping authority.
- No secrets in code. All credentials are passed via environment variables:
AZURE_TENANT_ID,AZURE_CLIENT_ID,AZURE_CLIENT_SECRET,E8CR_SIGNING_KEY. - No secrets in git. The CI pipeline checks for hardcoded
AZURE_CLIENT_SECRETassignments. - No secrets in MEMORY.md. Bot memory files must never contain credentials, tokens, or keys.
- One app registration per bot. Do not share client IDs/secrets across bots.
| Secret | Rotation frequency | Notes |
|---|---|---|
AZURE_CLIENT_SECRET |
Every 90 days or on compromise | Azure AD supports multiple active credentials for zero-downtime rotation |
E8CR_SIGNING_KEY |
Every 90 days or on compromise | Old manifests remain verifiable with the old key |
| SSH keys (for deployment) | Annually or on compromise | Use ed25519 keys |
# Use a .env file (never committed to git)
cat > /opt/e8cr/vmpm/.env <<'EOF'
AZURE_TENANT_ID=your-tenant-id
AZURE_CLIENT_ID=vmpm-app-client-id
AZURE_CLIENT_SECRET=vmpm-app-client-secret
E8CR_SIGNING_KEY=your-signing-key
EOF
chmod 600 /opt/e8cr/vmpm/.env
# Reference from systemd service
# EnvironmentFile=/opt/e8cr/vmpm/.env| Event | Log level | Example |
|---|---|---|
| Bot cycle start/complete | INFO | e8cr-vmpm cycle started at 2026-03-21T02:00:00Z |
| Graph API call | DEBUG | GET /deviceManagement/managedDevices → 200 (148 devices) |
| Evidence pack generated | INFO | manifest.json written, 7 files, signatureMode=hmac-sha256 |
| Compliance finding | WARN | P1: 3 critical vulnerabilities overdue >48h |
| Authentication failure | ERROR | Graph API auth failed: 401 Unauthorized |
| Permission denied | ERROR | Graph API 403: insufficient privileges for /users |
| Configuration change detected | WARN | Conditional Access policy "Require MFA" modified |
| Write action taken | WARN | Patch deployment initiated for KB5034441 (ring: pilot) |
- Local: Bot output directories contain per-cycle evidence JSON
- Centralised: Forward logs to your SIEM (Splunk, Sentinel, Elastic) via syslog or file shipping
- Immutable: Consider write-once storage for compliance evidence (Azure Immutable Blob, AWS S3 Object Lock)
- Evidence packs: Retain for the compliance assessment period plus one year (typically 2 years minimum)
- Operational logs: 90 days minimum, 1 year recommended
- Audit logs: Match your organisation's audit log retention policy (often 7 years for regulated industries)
The E8CR orchestrator and bot instances should never be directly accessible from the internet.
E8CR bots are outbound-only services. They:
- Pull data from Microsoft Graph API
- Query on-premises backup providers
- Write evidence to local storage
They do not serve HTTP endpoints, accept inbound connections, or expose APIs.
If you need to make compliance reports accessible to stakeholders:
- Serve the HTML reports from a separate web server with authentication
- Use your existing intranet or SharePoint
- Never expose the bot's working directory or evidence files without access control
Required outbound (HTTPS/443):
login.microsoftonline.com— Azure AD authenticationgraph.microsoft.com— Microsoft Graph APIservices.nvd.nist.gov— CISA KEV and NVD lookups (VM+PM bot only)epss.cyentia.com— EPSS scores (VM+PM bot only)- Greenbone/OpenVAS host (if using on-premises scanner)
- Veeam/Azure Backup endpoints (Backup bot only)
Required inbound: None.