Afunana
Afunana Documentation

Security Architecture

Authentication, RBAC, encryption, audit logging, and secret management.

← All docs

Afunana is an on-premise legacy-system intelligence platform. It reads the source that runs the business — COBOL, RPG, CL, DDS, SQL, and PL/SQL across IBM i, Oracle, and (roadmap) z/OS — and reconstructs the knowledge inside it. Because that source is often a bank's, insurer's, or government's most sensitive asset, security is a first-class design constraint, not a bolt-on.

The whole platform runs inside the customer's own network. Nothing about the analyzed systems leaves the customer boundary unless the customer explicitly configures an outbound integration (an LLM provider, a SIEM, or the source system itself). For fully air-gapped estates, Afunana runs offline against a local model with no vendor access at all — see On-Premise and Air-Gapped Operation.

This document describes the controls. Compliance & Standards maps those controls to OWASP, ISO/IEC 27001, and SOC 2.

Authentication

JWT Tokens

Password Security

Account Lockout

Repeated failed logins lock an account for a cooldown period. The lockout is persisted to the database, so it survives an application restart — an attacker cannot reset it by forcing a container bounce — and an in-memory tracker backs it up if the database write is unavailable.

Session Management

Parameter Value
Idle timeout Configurable; expires a session after a period of inactivity
Absolute session lifetime Configurable; ships at 30 days, enforced on every refresh and not extendable
Refresh mechanism a token-refresh call issues a fresh idle window, preserving the original session origin
Token revocation (per-token) On logout, the token is revoked and rejected thereafter
Token revocation (per-user) Admin can invalidate all of a user's sessions, or every session system-wide
Cross-tab sync Logout propagates across open browser tabs

Two independent clocks bound every session. The idle timeout expires a token after a period of inactivity; the frontend issues a refresh on user activity to extend it. The absolute lifetime (the fixed session origin plus the configured maximum age) is enforced on every refresh and cannot be extended — once the maximum session age is reached, the user must re-authenticate regardless of activity.

Revocation operates at two granularities. Per-token: logout records the token's unique identifier in the revocation store, and every authenticated request checks the presented token against it. Per-user: an administrator can revoke all active sessions for a named user (deactivation, credential compromise) or, in an emergency, force every user to re-authenticate. Both are exposed through the compliance surface and are fully audited. Expired revocation entries are cleaned up by a daily maintenance task.

Authorization

Role-Based Access Control (RBAC)

Four roles govern access throughout the system.

Role Permissions
admin Full access — user management, configuration, builds, chat, and all data.
qa Read access to analysis results, documentation, and project-management views. Cannot manage users or configuration.
user Read and chat access to assigned collections.
viewer Read-only access to analysis results and documentation for assigned collections.

Authorization is enforced in two layers:

Finer-grained access is enforced by per-collection access control lists. A user sees and queries only the collections assigned to them; the API enforces the collection boundary on data access, chat, and export. Role and collection ACL are independent — role sets what kind of operation is allowed, the ACL sets which collections it may touch.

Single Sign-On

Afunana supports OpenID Connect (OIDC) single sign-on. It has been used with Azure AD (Microsoft Entra ID), Okta, Google Workspace, and generic OIDC providers; provider discovery URLs for Azure/Okta/Google are built in, and any compliant provider works via an explicit discovery URL.

The authorization-code flow includes the following protections:

Operational controls:

The client secret is stored in configuration and masked when the SSO settings are read back through the admin API, and redacted in audit detail.

CSRF Protection

For the local (non-SSO) session, CSRF defense uses Origin validation. Every mutating request is checked against:

  1. The configured CORS origins.
  2. The FRONTEND_URL value from the database.
  3. The Host header of the incoming request.

Requests with a mismatched or missing Origin are rejected. Origins are resolved from multiple sources so that CORS keeps working across the supported deployment topologies (bundled Caddy, external proxy, separate proxy host) rather than depending on one static list.

Rate Limiting

Rate limiting is applied per client (keyed by remote address); exceeding a limit returns HTTP 429. Authentication endpoints (login, sign-up, forgot-password) carry the strictest per-endpoint limits, and a broader per-client request limit also applies across the API. Rate limiting works alongside account lockout: the rate limiter throttles request volume from an address, while lockout stops credential-guessing against a specific account.

Security Headers

The application itself sets the security headers (X-Frame-Options, HSTS, Content-Security-Policy, and more) in middleware — not the proxy — so they apply even behind a customer's own reverse proxy.

Header Value Purpose
Content-Security-Policy Restrictive policy Limits script/style/connect sources; mitigates XSS
Strict-Transport-Security max-age=31536000 Forces HTTPS for one year
X-Frame-Options DENY Prevents clickjacking
X-Content-Type-Options nosniff Prevents MIME-type sniffing
Referrer-Policy strict-origin-when-cross-origin Limits referrer leakage

Audit Logging

Audit logging is the backbone of Afunana's accountability story. Every security-relevant action funnels through a single logging entry point and lands in a dedicated audit table that is INSERT-only and tamper-evident.

Tamper-Evident Hash Chain

The audit log is a tamper-evident SHA-256 hash chain. Each record carries an integrity hash computed over the previous record's hash plus the current record's identifying fields (id, event id, timestamp, event type, actor, outcome). Because every record's hash links to the previous one, altering or deleting any historical record breaks the chain from that point forward, and the break is detectable. An optional external hash seed can anchor the chain when configured.

Immutability is enforced at the database layer, not just in application code: a database trigger blocks any UPDATE or DELETE of logged events and rolls the statement back. The only writer that may bypass it is the scheduled retention purge, which briefly suspends that protection, deletes only records past the retention window (and, when SIEM forwarding is on, only records already confirmed forwarded), then restores it — all under audit.

An integrity-verification routine walks the stored chain and reports whether it is intact and, if not, the id of the first mismatch. It is run on a schedule (below) and on demand through the compliance surface.

Event Categories

Seven categories are logged, each event attributed to an actor, IP, user agent, target, and outcome:

Category Examples
auth Login success/failure, logout, lockout, token refresh, password change/reset
authz Permission denied, role changes
data Collection/source access, build triggers, data and audit exports
chat Chat queries and errors (query text is logged only when chat-content auditing is explicitly enabled — off by default, for privacy)
admin User management, configuration changes, SSO changes, session revocation
system Startup/shutdown, deploy, errors, log purge
integrity Hash-chain verification results, checkpoint exports

Categories, minimum severity, and retention are all configurable in app_config.

SIEM Forwarding

Events can be forwarded to a customer SIEM in real time. Forwarding happens before the local insert (and the delivery timestamp is written into that same insert row), precisely because the immutability trigger forbids a later UPDATE.

Endpoint, port, protocol, and format are set in the admin UI or app_config.

Integrity & Retention Scheduler

A background scheduler runs automated compliance maintenance:

Interval Task
Hourly Hash-chain integrity check (recent records)
Daily Full hash-chain verification
Daily Checkpoint export (audit-state snapshot)
Daily Log purge (retention window; default 365 days, configurable)
Daily Expired-token-revocation cleanup

Integrity failures raise a critical event that itself forwards to the SIEM.

Secret Management

Secret resolution follows two deliberately different precedence chains, because bootstrap secrets are needed before the database is reachable.

Bootstrap keysDB_*, JWT_SECRET, SERVER_ROLE:

Priority Source
1 Docker secret
2 Environment variable
Never the database

These identify and unlock the database itself, so they cannot depend on it. The application fails loud at startup if a required bootstrap key is missing or invalid.

General secrets — API keys, SMTP credentials, SIEM tokens, and the like — resolve through a layered hierarchy. When an external secret vault is configured it is consulted first, above the on-box layers, with the environment as a final fallback:

Priority Source Notes
1 (highest) External secret vault (CyberArk CCP or HashiCorp Vault) When configured, secrets are resolved from the enterprise vault first
2 Writable on-box secrets layer Admin-UI-set values win, and take effect with no restart
3 Mounted container secret Read-only
4 Database configuration Cold-start fallback
5 (lowest) Environment variable Final fallback

A configured external vault (CyberArk CCP or HashiCorp Vault) is consulted first; otherwise the runtime path is the configuration cache with the on-box writable layer, mounted secrets, and finally the environment as fallbacks. The writable on-box layer lets an operator set or rotate a secret through the admin UI and have it apply immediately. Secrets are never logged, and sensitive keys (DB password, JWT_SECRET, deploy secret, API keys) are masked in audit detail.

Encryption

In Transit

At Rest

Container Security

On-Premise and Air-Gapped Operation

Afunana is designed to run entirely inside the customer's perimeter with zero vendor access to the analyzed systems or data.

Vulnerability Scanning

Every deploy runs three scanners:

Tool Scope Purpose
pip-audit Python dependencies Known-CVE detection
npm audit JavaScript dependencies Known-CVE detection
Bandit Python source Static analysis (SAST)

Scans are non-fatal — results are recorded but do not block a deploy — so awareness is continuous without a low-severity finding halting a production release. The decision to act on a finding stays with the operator.

Configurable Quality Checks

The code-quality check catalog is configurable per check (exposed via admin check-settings endpoints). Each check can be set to error, note, or off, controlling whether and how it surfaces as a finding.

Because the catalog and its per-check severities live in app_config, changes are governed by the same admin authorization and audit logging as all other configuration — making the organization's active quality posture an auditable control rather than a hidden default.

MCP Authentication

The Model Context Protocol server (over SSE) is protected by OAuth 2.0 Authorization Code with PKCE, so external assistants (Claude, Cursor, Copilot, claude.ai) connect under the same identity model as the web UI.