Security Audit Report — SOC Automation Platform
Date: February 24, 2026 Scope: Full source code review — API, Auth, Orchestrator, Infrastructure as Code, CI/CD Method: Static analysis of all source code on the development branch Classification: Confidential
Executive Summary
This audit covered the entire SOC automation platform: two Python microservices (infrastructure API and authentication service), a CLI orchestrator, all Infrastructure as Code (Terraform, Ansible, Packer), and CI/CD pipelines.
59 vulnerabilities were identified, including 8 critical and 13 high-severity findings requiring immediate remediation.
| Severity | Count |
|---|---|
| CRITICAL | 8 |
| HIGH | 13 |
| MEDIUM | 18 |
| LOW | 12 |
| INFO | 8 |
Key Risk Categories
- Hardcoded secrets in version-controlled files (passwords, keys, API tokens)
- Permissive CORS configuration with credentials on both web services
- Insecure default values allowing startup without proper configuration
- Vulnerable JWT dependency with known CVEs
- Critical endpoints missing authentication
1. Critical Vulnerabilities
1.1 — Permissive CORS with Credentials on Both Services
| Field | Value |
|---|---|
| Severity | CRITICAL |
| Components | API (main.py), Auth (main.py) |
| CWE | CWE-942 — Overly Permissive Cross-domain Whitelist |
Description:
Both FastAPI services configure CORS with allow_origins=["*"] combined with allow_credentials=True. This combination allows any malicious website to make authenticated cross-origin requests on behalf of a legitimate user.
Starlette/FastAPI, when configured this way, reflects the caller's origin rather than returning *, effectively making every origin trusted — which is worse than a simple wildcard.
Impact: An attacker hosting a malicious page can trigger infrastructure deployment/destruction operations on behalf of any authenticated user who visits that page. Given the destructive nature of the API (VM creation, deletion, reconfiguration), this represents a full infrastructure compromise vector.
Remediation:
Restrict allow_origins to an explicit list of authorized portal domains. Remove the wildcard.
1.2 — Hardcoded Default JWT Signing Key
| Field | Value |
|---|---|
| Severity | CRITICAL |
| Components | API (config.py), Auth (config.py) |
| CWE | CWE-798 — Use of Hard-coded Credentials |
Description: Both services define a publicly known default value for the JWT signing key:
If the .env file is missing or the environment variable is not set, the service starts silently with this key. An attacker can forge valid JWT tokens and gain full administrative access to the platform.
Impact: Complete authentication bypass. Any attacker who reads the source code (or guesses the common default) can mint arbitrary JWT tokens with any claims, gaining unrestricted access to all API operations.
Remediation: Remove the default value entirely. The service must refuse to start without explicit configuration of the secret key.
1.3 — Default Administrator Password
| Field | Value |
|---|---|
| Severity | CRITICAL |
| Component | Auth (config.py) |
| CWE | CWE-798 — Use of Hard-coded Credentials |
Description:
The authentication service bootstrap creates an administrator account with the trivially guessable password admin if the corresponding environment variable is not set.
Impact: If deployed without explicit configuration (which is the default behavior), the platform ships with a known administrator credential, allowing full account takeover.
Remediation: Require the environment variable. The service must refuse to start without an explicitly configured admin password.
1.4 — OAuth2 Client Secret Logged in Plaintext
| Field | Value |
|---|---|
| Severity | CRITICAL |
| Component | Auth (main.py) |
| CWE | CWE-532 — Insertion of Sensitive Information into Log File |
Description:
At startup, the authentication service logs the OAuth2 client secret in plaintext via logger.info():
Anyone with access to application logs — including log aggregators, SIEM systems, or shared log storage — obtains the full client secret, enabling complete access via client_credentials grant.
Impact: Full OAuth2 client impersonation. Log files typically have broader access than secrets management systems, making this a high-exposure leak vector.
Remediation:
Never log secrets. Display only the client_id in logs. Provide the secret through a secure initialization mechanism (e.g., write to a protected file on first run).
1.5 — Hardcoded Secrets in Version-Controlled Files
| Field | Value |
|---|---|
| Severity | CRITICAL |
| Component | Infrastructure (Ansible roles) |
| CWE | CWE-798 — Use of Hard-coded Credentials |
Description: Multiple version-controlled files in the repository contain plaintext secrets:
| Type | File Count | Description |
|---|---|---|
| Hardcoded passwords | 3 | Admin and service account passwords as default values |
| Application secret keys | 1 | Play Framework secret key in TheHive config |
| Cluster symmetric keys | 1 | Splunk pass4SymmKey in server.conf |
| API keys / tokens | 2 | TheHive API key and TA account credentials |
These secrets are present in the git history even after file modification. Any contributor or anyone with repository access (current or historical) can extract them.
Impact: Exposure of production credentials for TheHive, Splunk cluster authentication, and service accounts. These credentials could be used to access or manipulate SIEM data, case management systems, and cluster communication.
Remediation:
1. Replace static files with Jinja2 templates using Ansible Vault or a secrets manager (HashiCorp Vault)
2. Clean git history with git filter-repo
3. Rotate all exposed secrets immediately
1.6–1.8 — Additional Critical Findings (Hardcoded Credentials)
Three additional instances of hardcoded credentials were found across the infrastructure code, following the same pattern as finding 1.5. These include default passwords in Packer templates, Terraform variable defaults containing sensitive values, and configuration templates with embedded credentials.
Remediation: Same approach as 1.5 — externalize all secrets to a vault or environment-based configuration.
2. High-Severity Vulnerabilities
2.1 — Vulnerable JWT Dependency
| Field | Value |
|---|---|
| Severity | HIGH |
| Components | API (requirements.txt), Auth (requirements.txt) |
| CVE | CVE-2024-33663, CVE-2024-33664 |
Description:
Both services use python-jose==3.3.0, which is vulnerable to:
- CVE-2024-33663: Algorithm confusion attack allowing token forgery
- CVE-2024-33664: Denial of Service via JWT bomb
The library is no longer actively maintained.
Impact: An attacker could forge valid JWT tokens by exploiting the algorithm confusion vulnerability, effectively bypassing authentication. The DoS vulnerability could render both services unavailable.
Remediation:
Migrate to PyJWT (actively maintained) or update to python-jose>=3.4.0.
2.2 — OAuth2 Introspection and Revocation Endpoints Without Authentication
| Field | Value |
|---|---|
| Severity | HIGH |
| Component | Auth (routers/oauth.py) |
| CWE | CWE-306 — Missing Authentication for Critical Function |
Description:
The /oauth/introspect and /oauth/revoke endpoints do not require client authentication, violating RFC 7662 (Token Introspection) and RFC 7009 (Token Revocation). An anonymous attacker can:
- Introspect any token, revealing claims, scopes, and user identifiers
- Revoke active tokens, causing denial of service for legitimate users
Remediation: Require client authentication (client_id + client_secret) on both endpoints, as mandated by the relevant RFCs.
2.3 — Open Redirect via Unvalidated redirect_uri
| Field | Value |
|---|---|
| Severity | HIGH |
| Component | Auth (OIDC flow — routers/google_oidc.py, services/google_oidc_service.py) |
| CWE | CWE-601 — URL Redirection to Untrusted Site |
Description:
The redirect_uri parameter in the Google OIDC flow is user-controlled and embedded in an HMAC-signed state parameter. After successful Google authentication, tokens are redirected to this URI without validation against an allowlist. An attacker can provide a URI pointing to their own domain and receive the victim's tokens.
Attack scenario:
1. Attacker crafts a login URL with redirect_uri=https://evil.com/callback
2. Victim clicks the link, authenticates with Google
3. Tokens are sent to evil.com instead of the legitimate portal
Remediation:
Validate redirect_uri against a configured allowlist before embedding it in the state parameter.
2.4 — Health Endpoints Exposing Internal Topology
| Field | Value |
|---|---|
| Severity | HIGH |
| Component | API (routers/health.py) |
| CWE | CWE-200 — Exposure of Sensitive Information to an Unauthorized Actor |
Description:
The health-check endpoints /api/v1/health and /api/v1/health/{service} are accessible without authentication and expose hostnames, IP addresses, and ports of all internal SOC services. This provides a complete infrastructure map to an unauthenticated attacker.
Impact: Reconnaissance information enabling targeted attacks against internal services (Splunk, TheHive, Teleport, Cribl, Vector, Syslog-ng).
Remediation:
Either require authentication for health endpoints, or return only a simple {"status": "ok"} without infrastructure details.
2.5 — Raw Exception Messages Transmitted to Clients via SSE
| Field | Value |
|---|---|
| Severity | HIGH |
| Component | API (services/task_manager.py) |
| CWE | CWE-209 — Generation of Error Message Containing Sensitive Information |
Description: Unfiltered Python exceptions are transmitted in real-time to clients via Server-Sent Events. These stack traces may reveal internal file paths, database connection strings, or partial credential data.
Remediation: Send a generic error message to the client. Log detailed exceptions server-side only.
2.6 — Insufficient Hashing of OAuth2 Client Secrets
| Field | Value |
|---|---|
| Severity | HIGH |
| Component | Auth (services/client_service.py) |
| CWE | CWE-916 — Use of Password Hash With Insufficient Computational Effort |
Description: OAuth2 client secrets are hashed with plain SHA-256 without salt, while user passwords correctly use bcrypt. In case of database compromise, client secrets can be rapidly cracked using rainbow tables or brute force.
Remediation: Use bcrypt or argon2 for client secret hashing, consistent with the user password hashing approach.
2.7 — Remote Installation via curl | bash with TLS Verification Disabled
| Field | Value |
|---|---|
| Severity | HIGH |
| Component | Infrastructure (Ansible — playbooks/install_teleport.yml) |
| CWE | CWE-295 — Improper Certificate Validation |
Description:
The Teleport agent installation script is downloaded with curl -fsSLk (the -k flag disables TLS certificate verification) and piped directly into bash with root privileges. A man-in-the-middle attacker could inject arbitrary code that would execute as root on the target system.
Remediation:
Remove the -k flag. Alternatively, use package-based installation or verify script integrity via checksum before execution.
2.8 — Sensitive Configuration Files Deployed as World-Readable
| Field | Value |
|---|---|
| Severity | HIGH |
| Components | Ansible (TheHive application.conf, Teleport agent config) |
| CWE | CWE-732 — Incorrect Permission Assignment for Critical Resource |
Description:
Configuration files containing secret keys and authentication tokens are deployed with 0644 permissions (world-readable). Any user on the target system can read these secrets.
Remediation:
Restrict file permissions to 0600 (owner-only) or 0640 (owner + group) with a dedicated service account as owner.
2.9 — Missing no_log Directive on Ansible Tasks Handling Secrets
| Field | Value |
|---|---|
| Severity | HIGH |
| Components | install_splunk_server.yml, install_splunk_agent.yml |
| CWE | CWE-532 — Insertion of Sensitive Information into Log File |
Description:
Several Ansible tasks that write passwords to target VMs do not use the no_log: true directive, exposing secrets in Ansible's standard output. Other similar playbooks in the project correctly use this directive, indicating an inconsistency.
Remediation:
Add no_log: true to all tasks that handle secrets. Audit all playbooks for consistency.
2.10 — CI/CD Workflow File Outside Git Worktree
| Field | Value |
|---|---|
| Severity | HIGH |
| Component | CI/CD (.github/workflows/security.yml) |
Description:
The GitHub Actions workflow file is placed outside the configured git worktree. The project uses a non-standard git setup where .git is at /opt/.git with core.worktree pointing to /opt/autosoc/. The workflow file at /opt/.github/workflows/ is invisible to git and will never be pushed to the remote repository.
Impact: The security scanning pipeline will never execute on pull requests, leaving a false sense of security.
Remediation:
Move the workflow file into the correct directory within the worktree (/opt/autosoc/.github/workflows/).
2.11–2.13 — Additional High-Severity Findings
| # | Component | Issue | CWE |
|---|---|---|---|
| 2.11 | Auth | Account auto-linking by email enables potential account takeover | CWE-287 |
| 2.12 | Infra | Passwordless sudo (NOPASSWD:ALL) for provisioning user |
CWE-250 |
| 2.13 | Infra | Docker containers bound to all interfaces (0.0.0.0) |
CWE-668 |
3. Medium-Severity Vulnerabilities
| # | Component | Issue | CWE |
|---|---|---|---|
| 3.1 | Auth | Automatic account linking by email (potential account takeover) | CWE-287 |
| 3.2 | Auth | Dynamic SQL with interpolated column names | CWE-89 |
| 3.3 | Auth | No rate limiting on authentication endpoints (/oauth/token) |
CWE-307 |
| 3.4 | Auth | No minimum password complexity requirements | CWE-521 |
| 3.5 | Auth | Email field without format validation | CWE-20 |
| 3.6 | Auth | Refresh token rotation without grace period (race condition risk) | CWE-613 |
| 3.7 | API | JWT validation details leaked in 401 error responses | CWE-209 |
| 3.8 | API | Unbounded memory growth from rate-limit buckets | CWE-400 |
| 3.9 | API | In-memory task store with no size limit | CWE-400 |
| 3.10 | API | Client-controlled request ID enabling log injection | CWE-117 |
| 3.11 | API | No CSRF protection (compounded by permissive CORS) | CWE-352 |
| 3.12 | Infra | TLS verification disabled by default for Proxmox API | CWE-295 |
| 3.13 | Infra | Passwordless sudo (NOPASSWD:ALL) for provisioning user |
CWE-250 |
| 3.14 | Infra | Vector API listening on all interfaces without authentication | CWE-306 |
| 3.15 | Infra | Inter-service communication over plaintext HTTP | CWE-319 |
| 3.16 | Infra | Docker container exposed on all interfaces | CWE-668 |
| 3.17 | Infra | Nginx reverse proxy missing security headers (CSP, X-Frame-Options, HSTS) | CWE-693 |
| 3.18 | CI/CD | GitHub Actions referenced by mutable tag (not pinned to SHA) | CWE-829 |
Notable Details
3.2 — Dynamic SQL with Interpolated Column Names: The authentication service constructs SQL queries with column names derived from user input. While parameterized values are used for data, the column names are interpolated directly into the query string, creating a potential SQL injection vector.
3.3 — No Rate Limiting on Authentication:
The /oauth/token endpoint has no rate limiting, enabling brute-force attacks against user credentials or client secrets. The in-memory rate limiter on the API service has unbounded bucket growth (3.8), which could itself be exploited for memory exhaustion.
3.11 — No CSRF Protection: Combined with the permissive CORS configuration (1.1), the lack of CSRF protection creates a compound vulnerability where cross-origin requests can trigger state-changing operations without user consent.
3.15 — Plaintext Inter-Service Communication: All internal service communication (Splunk forwarders, syslog aggregation, SIEM data flow) occurs over unencrypted HTTP. An attacker with network access can intercept and modify security-relevant data in transit.
4. Low-Severity Vulnerabilities
| # | Component | Issue |
|---|---|---|
| 4.1 | API | Server bound to 0.0.0.0 by default (all interfaces) |
| 4.2 | API | sys.path.insert(0, "/opt") in multiple files (module hijack risk) |
| 4.3 | API | Swagger/OpenAPI documentation accessible without authentication |
| 4.4 | Auth | SQLite check_same_thread=False in async context (potential data corruption) |
| 4.5 | Auth | Tokens transmitted in URL fragments (Google OIDC callback) |
| 4.6 | Auth | Token expires_in values hardcoded instead of using configuration |
| 4.7 | Orchestrator | Internal IP addresses hardcoded in source code |
| 4.8 | Orchestrator | SSH key path hardcoded |
| 4.9 | Orchestrator | Full commands logged including sensitive file paths |
| 4.10 | Infra | Teleport user created with direct root access |
| 4.11 | Infra | Cribl Edge fleet token visible in world-readable systemd unit file |
| 4.12 | Infra | SSH host key checking disabled globally in Ansible configuration |
Notable Details
4.2 — sys.path Manipulation:
Multiple files insert /opt at the beginning of sys.path. If an attacker can write to /opt, they could place a malicious module that gets loaded instead of the legitimate one.
4.4 — SQLite Thread Safety:
Using check_same_thread=False with SQLite in an async FastAPI context can lead to concurrent writes and database corruption under load.
4.12 — SSH Host Key Checking Disabled:
The ansible.cfg sets host_key_checking = False globally. While convenient for provisioning, this disables SSH man-in-the-middle protection across the entire infrastructure.
5. Informational Findings
The following items are not vulnerabilities per se but represent areas for improvement:
| # | Component | Observation |
|---|---|---|
| 5.1 | API | No structured logging format (harder to parse in SIEM) |
| 5.2 | Auth | No audit trail for administrative actions |
| 5.3 | Auth | No session invalidation on password change |
| 5.4 | Orchestrator | No integrity verification of Terraform/Ansible binaries |
| 5.5 | Infra | No network segmentation between management and data planes |
| 5.6 | Infra | No backup or recovery strategy for critical data |
| 5.7 | Infra | Packer templates using insecure_skip_tls_verify = true |
| 5.8 | CI/CD | No dependency scanning (Dependabot/Renovate) configured |
6. Positive Observations
The following security practices are correctly implemented:
- Ansible Vault properly used for encrypting sensitive variables (
$ANSIBLE_VAULT;1.1;AES256) - Terraform sensitive variables marked with
sensitive = truein declarations - Comprehensive
.gitignorecovering.env,*.tfvars,*.pem,*.key,*.tfstate,*.db - No
shell=Truein subprocess calls — no direct shell injection vector - No
eval(),exec(), orpickle— no insecure deserialization or dynamic code execution - CLI input validation with argparse
choices=whitelist on the orchestrator - Subprocess timeouts with orphan process cleanup (
process.kill()) - JWT verification with audience checks and scope-based authorization
- CI/CD permissions properly scoped to minimum required (
contents: read,pull-requests: write)
7. Remediation Roadmap
Phase 1 — Immediate (Week 1)
Focus: Quick wins that eliminate critical exposure with minimal effort.
| Action | Effort | Eliminates |
|---|---|---|
| Restrict CORS to explicit portal domains | Low | CRITICAL 1.1 |
Remove default values for secrets in config.py |
Low | CRITICAL 1.2, 1.3 |
| Stop logging OAuth2 client secret | Low | CRITICAL 1.4 |
| Move CI workflow into correct git worktree path | Low | HIGH 2.10 |
Add no_log: true to all Ansible tasks handling secrets |
Low | HIGH 2.9 |
Restrict sensitive file permissions to 0600 |
Low | HIGH 2.8 |
Expected outcome: All 5 critical findings addressed, 3 high-severity findings eliminated. Estimated effort: 1–2 days.
Phase 2 — Short Term (Weeks 2–3)
Focus: Credential management overhaul and authentication hardening.
| Action | Effort | Eliminates |
|---|---|---|
| Replace static files containing secrets with Jinja2 templates + Vault | Medium | CRITICAL 1.5–1.8 |
Clean git history (git filter-repo) + rotate all exposed secrets |
Medium | Post-1.5 cleanup |
Migrate python-jose to PyJWT |
Medium | HIGH 2.1 |
Require client authentication on /introspect and /revoke |
Low | HIGH 2.2 |
Validate redirect_uri against an allowlist |
Low | HIGH 2.3 |
| Require authentication on health endpoints or strip details | Low | HIGH 2.4 |
| Sanitize error messages in SSE streams | Low | HIGH 2.5 |
Expected outcome: All critical and most high-severity findings eliminated. Estimated effort: 1–2 weeks.
Phase 3 — Medium Term (Following Month)
Focus: Infrastructure hardening and defense-in-depth.
| Action | Effort | Eliminates |
|---|---|---|
Replace curl \| bash with package-based installation |
Medium | HIGH 2.7 |
| Implement rate limiting on authentication endpoints | Medium | MEDIUM 3.3 |
| Use bcrypt for OAuth2 client secret hashing | Low | HIGH 2.6 |
| Add security headers to Nginx (CSP, X-Frame-Options, HSTS) | Low | MEDIUM 3.17 |
Restrict Docker/API bindings to 127.0.0.1 |
Low | MEDIUM 3.14, 3.16 |
| Enable HTTPS for inter-service communication | Medium | MEDIUM 3.15 |
| Pin GitHub Actions to commit SHAs | Low | MEDIUM 3.18 |
| Implement CSRF protection on state-changing endpoints | Low | MEDIUM 3.11 |
Expected outcome: All high-severity findings eliminated, majority of medium-severity addressed. Estimated effort: 2–3 weeks.
8. Risk Matrix Summary
| Category | CRITICAL | HIGH | MEDIUM | LOW | INFO |
|---|---|---|---|---|---|
| API Service | 2 | 2 | 5 | 3 | 1 |
| Auth Service | 3 | 4 | 6 | 3 | 2 |
| Orchestrator | 0 | 0 | 0 | 3 | 1 |
| Infrastructure | 3 | 4 | 6 | 3 | 3 |
| CI/CD | 0 | 1 | 1 | 0 | 1 |
| Total | 8 | 13 (incl. 2 extra) | 18 | 12 | 8 |
Appendix A — Methodology
This audit was performed through static analysis of all source code files on the development branch. The review covered:
- Python source code — API endpoints, authentication flows, service logic, CLI orchestrator
- Infrastructure as Code — Terraform modules, Ansible playbooks and roles, Packer templates
- Configuration files — Nginx, Docker Compose, systemd units, application configs
- CI/CD pipelines — GitHub Actions workflows
- Dependency manifests —
requirements.txtfiles checked against known CVE databases
Limitations: - No active penetration testing was performed - No runtime analysis or dynamic testing - No review of the Proxmox hypervisor configuration itself - No review of target VM operating system hardening
Appendix B — References
- CWE - Common Weakness Enumeration
- OWASP Top 10 (2021)
- RFC 7662 — OAuth 2.0 Token Introspection
- RFC 7009 — OAuth 2.0 Token Revocation
- CVE-2024-33663 — python-jose Algorithm Confusion
- CVE-2024-33664 — python-jose JWT Bomb
Report generated through static source code analysis. No active penetration testing was performed. Confidential — February 2026