Skip to content

Security Dossier (CISO)

Classification: Restricted β€” CISO / Security Team
Version: 1.1
Date: 2026-05-23
Audience: CISO, Security Officers, Security Engineering


Security overview

Repod is an enterprise-grade Linux package repository manager (APT and RPM editions). It provides full control over the software supply chain, from package intake to distribution to target systems.

Security principles

  • Defense in depth β€” every incoming package traverses a multi-stage, independent control pipeline (antivirus β†’ CVE β†’ GPG β†’ integrity).
  • Least privilege β€” five distinct roles with precisely scoped permission boundaries.
  • Separation of duties β€” CVE remediation decisions are reserved for the security team; operators cannot self-approve vulnerable packages.
  • Full traceability β€” every sensitive action is recorded in append-only JSONL audit files that cannot be modified or deleted via the API.
  • Regulatory alignment β€” NIS2 (EU 2022/2555), ANSSI SecNumCloud, GDPR.

Core components

Component Technology Role
Backend API FastAPI / Python 3.11 Business logic, authentication, security pipeline
Database SQLite (WAL mode) Users, packages, tokens, CVE records
Antivirus ClamAV 1.4.3 Malware detection on every upload
CVE scanner Grype v0.112.0 (Anchore) Known vulnerability analysis
SBOM generator Syft v1.44.0 CycloneDX 1.5 + SPDX 2.3 per package
Frontend React + Nginx CISO / operator interface
Storage Docker volume /repos Packages, manifests, audit logs, GPG keyrings

Authentication and identity management

Local authentication

  • Password storage: bcrypt via passlib[bcrypt]. No plaintext passwords stored anywhere.
  • Password policy (enforced server-side):
    • Minimum 8 characters
    • At least 1 uppercase letter AND at least 1 digit or special character
  • Password reset: tokens stored as SHA-256 hashes only. Valid for 30 minutes.
  • Account status: is_active verified on every authenticated request. Deactivating an account immediately invalidates all active sessions.

JWT tokens (user sessions)

Property Value
Algorithm HS256
Lifetime 60 minutes (configurable via JWT_EXPIRE_MINUTES)
Secret key validation Application refuses to start if JWT_SECRET_KEY is empty or a default value when ENV=production
Per-request check Active status verified on every request, not only at token creation

Known limitation β€” no JWT revocation

A valid token remains functional until natural expiry (60 min) even after explicit logout. Compensating control: the 60-minute window limits exploitation exposure; account deactivation is checked on every request.

API tokens (CI/CD)

Property Value
Format repod_ prefix + cryptographically secure random suffix
Storage SHA-256 hash only β€” plaintext never persisted
Expiry Configurable per token (optional)
Revocation Immediate, by admin or token owner

LDAP / Active Directory (optional)

Property Value
Library ldap3
TLS Certificate verification enabled by default (verify_cert=True)
Auto-provisioning Local account created on first successful LDAP login with a random, non-usable local password
Bind password masking Masked as *** in GET /settings responses

Rate limiting

Endpoint Limit
Authentication (/auth/*) 10 req / min
Package upload 20 req / min
Import / fetch 10 req / min
Batch operations 5 req / min
Repository sync 3 req / min

Access control (RBAC)

Five privilege levels with precisely scoped permissions:

Permission admin maintainer uploader auditor reader
User management βœ… ❌ ❌ ❌ ❌
Settings modification βœ… ❌ ❌ ❌ ❌
Package upload βœ… βœ… βœ… ❌ ❌
Package import βœ… βœ… βœ… ❌ ❌
Package promotion / deletion βœ… βœ… ❌ ❌ ❌
Repository sync βœ… βœ… ❌ ❌ ❌
CVE decision (approve/reject) βœ… βœ… ❌ ❌ ❌
Audit log access βœ… βœ… ❌ βœ… ❌
Package read access βœ… βœ… βœ… βœ… βœ…
SBOM export βœ… βœ… ❌ βœ… ❌
API token management βœ… (all) βœ… (own) βœ… (own) ❌ ❌

admin β€” full platform access. Only role that can manage users, change system settings, and configure CVE policies.

maintainer β€” full package lifecycle. Can approve/reject CVE-flagged packages. Cannot manage users or system settings.

uploader β€” upload and import packages only. Designed for CI/CD pipelines requiring minimal access.

auditor β€” read-only access to packages and audit logs. Suitable for compliance teams and external auditors.

reader β€” read-only access to packages only. No audit log access.


Package security pipeline

Every incoming package traverses a 6-stage sequential pipeline before publication.

flowchart TD
    A([Package received]) --> B[Stage 1\nFormat validation]
    B -->|FAIL| R1([Rejected β€” HTTP 400])
    B --> C[Stage 2\nSHA-256 provenance check]
    C -->|MISMATCH| R2([Rejected])
    C --> D[Stage 3\nClamAV antivirus scan]
    D -->|VIRUS| Q1([Quarantined])
    D --> E[Stage 4\nGrype CVE analysis\n+ EPSS + CISA KEV]
    E -->|policy=block| Q2([Quarantined])
    E -->|policy=review| PR([pending_review\nCISO queue])
    E --> F[Stage 5\nGPG signature verification]
    F -->|INVALID| R3([Rejected])
    F --> G[Stage 6\nDependency check]
    G --> PUB([Published to repository])

Stage-by-stage description

Stage 1 β€” Format validation Verifies structural integrity of the package file:

dpkg-deb --info β€” rejects malformed, truncated, or non-compliant .deb files.

rpm -qp --info β€” rejects malformed or corrupt .rpm files.

Stage 2 β€” SHA-256 provenance check
Compares the uploaded package hash against the source repository index. Any mismatch results in immediate rejection.

Stage 3 β€” ClamAV antivirus scan
Submitted to ClamAV (signature database updated daily by freshclam). Malware detection triggers quarantine and blocks publication.

Stage 4 β€” Grype CVE scan
Grype cross-references the package SBOM against NVD, GitHub Advisory Database, and CISA KEV. Response is determined by the configured policy:

Severity Policy Behavior
Critical block Quarantined β€” never published
Critical review pending_review β€” mandatory CISO queue
High block Quarantined
High review pending_review β€” CISO queue
Medium warn Published with warning flag
Low allow Published without restriction

Policies are configurable per-severity by administrators.

Stage 5 β€” GPG signature verification
If a detached signature is present, it is verified against the keyring. A present-but-invalid signature is a hard failure. An absent signature is a soft pass (not all packages carry detached signatures).

Stage 6 β€” Dependency availability check
Verifies declared dependencies against the internal pool. Missing dependencies generate a warning (non-blocking by default; set strict_deps=true for air-gapped environments).


Vulnerability management (CVE)

CISO review queue

Packages where at least one CVE triggers the review policy enter pending_review status. They are visible in the CISO interface but inaccessible to repository consumers until a decision is made.

Available actions (roles: admin, maintainer):

  • Approve β€” package published; justification mandatory and recorded.
  • Reject β€” package moved to quarantine; justification mandatory and recorded.

SLA by severity

Severity Default SLA Configurable
Critical 0 days (immediate decision required) Yes
High 30 days Yes
Medium 90 days Yes
Low No SLA Yes

SLA breaches surface as alerts in the admin interface. Email and webhook notifications are available for SLA breach events.

CVE contextual enrichment

Each CVE in the CISO review queue displays:

  • CVSS v3 score (base + attack vector)
  • EPSS score (30-day exploitation probability)
  • CISA KEV catalog membership
  • Affected package, version, and available fix
  • Previous decision justification (if re-reviewed)

SBOM and software traceability

Supported formats

Standard Version Body
CycloneDX 1.5 OWASP
SPDX 2.3 ISO/IEC 5962:2021

SBOM contents

Each generated SBOM contains:

  • Complete component inventory (direct and transitive dependencies)
  • Associated CVE identifiers and their triage status
  • SHA-256 hash of each component
  • Vendor metadata, version, SPDX license identifier
  • Generation timestamp and last CVE scan timestamp

Regulatory alignment

Framework Article / Section Coverage
NIS2 (EU 2022/2555) Article 21 β€” supply chain security Software inventory, vulnerability management
ANSSI SecNumCloud Software inventory Component traceability
Executive Order 14028 (US) SBOM for delivered software Reference only

SBOM API

# Per-package SBOM (CycloneDX)
curl -H "Authorization: Bearer $TOKEN" \
  "http://localhost:8000/sbom/nginx/1.24.0?format=cyclonedx&arch=amd64"

# Full repository SBOM
curl -H "Authorization: Bearer $TOKEN" \
  "http://localhost:8000/sbom/export?format=cyclonedx"

Audit trail

Format and storage

Property Value
Format JSONL (JSON Lines) β€” one event per line
Organization One file per day: /repos/audit/YYYY-MM-DD.jsonl
Access Read-only; roles admin, maintainer, auditor
Write mode Append-only β€” no modification or deletion API
Retention Configurable (default: 90 days)

Event structure

{
  "timestamp": "2026-05-23T14:32:01.412000+00:00",
  "action": "UPLOAD",
  "user": "john.doe",
  "result": "SUCCESS",
  "package": "nginx",
  "version": "1.24.0",
  "detail": "status=pending_review | cve_findings=2"
}

Logged event types

Event Trigger
LOGIN Authentication attempt β€” result includes source IP
USER_CREATE Account creation (local or LDAP auto-provision)
USER_UPDATE Account modification (role, status, email)
USER_DELETE Account deletion
PASSWORD_CHANGE User-initiated password change
PASSWORD_RESET Admin-initiated or token-based password reset
UPLOAD Package upload (pipeline results included)
VALIDATE Validation pipeline failure detail
DELETE Package deletion
IMPORT Import from an external repository
SYNC Repository index synchronization
SECURITY_DECISION CVE approve/reject decision with justification
RESCAN Package re-scanned for CVEs
CLAMAV_UPDATE Antivirus signature database update
INIT_DISTS Distribution initialized

GDPR note

Audit logs include user IP addresses (personal data under GDPR). Retention must be aligned with the organization's internal data retention policy. Legal basis for processing: legitimate interest / NIS2 legal obligation.


Infrastructure hardening

Containerization

Measure Status Detail
Docker socket not mounted βœ… Backend has no access to /var/run/docker.sock
Source code not mounted in production βœ… Only /repos volume mounted
Non-root user βœ… Backend runs as appuser (UID 1000)
GPG via shared volume βœ… /repos/gnupg shared without Docker socket

FastAPI application

Measure Status Detail
Swagger UI disabled in production βœ… ENV=production β†’ /docs returns 404
Hot-reload disabled βœ… uvicorn starts without --reload
JWT secret validation at startup βœ… Refuses to start with default/empty key
Secret masking in /settings βœ… SMTP and LDAP passwords masked as ***

HTTP security headers

Header Value
X-Frame-Options SAMEORIGIN
X-Content-Type-Options nosniff
X-XSS-Protection 1; mode=block
Referrer-Policy strict-origin-when-cross-origin
Content-Security-Policy default-src 'self'; script-src 'self' 'unsafe-inline'; …
Permissions-Policy camera=(), microphone=(), geolocation=(), payment=()

CSP unsafe-inline

'unsafe-inline' is present in script-src and style-src due to React's use of inline styles. Migration to a nonce-based CSP is planned for v3.


Known limitations and compensating controls

No JWT revocation

Risk Medium
Description JWT tokens remain valid until expiry (60 min) after logout or deactivation
Compensating control Account deactivation is verified on every request; 60-minute window limits exposure
Planned fix Redis-based token blacklist in v2.x

No HTTPS in default configuration

Risk High (if deployed without reverse proxy)
Description TLS termination is delegated to a reverse proxy
Compensating control Mandatory deployment behind Nginx / Traefik / Caddy
Documentation Reverse proxy guide β†’

Backend port exposed on all interfaces

Risk Medium (without reverse proxy)
Description Port 8000 bound to all interfaces by default
Compensating control Set BIND_HOST=127.0.0.1 in .env + firewall rules

CSP with unsafe-inline

Risk Low (internal interface, no user-controlled script input)
Planned fix Nonce-based CSP in v3

Compliance checklist

NIS2 (EU 2022/2555)

Requirement Status Implementation
Supply chain security βœ… CVE pipeline, SBOM, GPG signing, antivirus
Vulnerability management βœ… Grype, CISO queue, configurable SLA, EPSS, CISA KEV
Logging and monitoring βœ… JSONL audit trail, configurable retention, 19 event types
Access control βœ… 5-role RBAC, JWT, API tokens
Incident handling ⚠️ Audit trail present β€” internal IR procedure required at org level
Encryption in transit ⚠️ Delegated to reverse proxy
Business continuity ❌ To be defined at organization level
Security testing ❌ Penetration test / code review to be scheduled

ANSSI SecNumCloud

Requirement Status Implementation
Software inventory βœ… CycloneDX 1.5 + SPDX 2.3 per package
Audit logs βœ… Append-only JSONL, configurable retention
Access control βœ… RBAC, least privilege
Environment separation ⚠️ Docker containers β€” network isolation to be reinforced
Encryption at rest ❌ /repos volume unencrypted β€” manage at OS/infrastructure level
Key management ⚠️ Integrated GPG, validated JWT secret β€” HSM not included

GDPR

Requirement Status Implementation
Data minimization βœ… Only email, role, and IP address collected
Data retention βœ… Configurable (default 90 days)
Data security βœ… bcrypt hashing, restricted access
Records of processing activities ❌ To be documented by the organization

Vulnerability reporting

Security vulnerabilities must be reported through a confidential channel.

Contact: security@[organization]
Channel: Do not use the public issue tracker.
Response SLA: 72 hours for acknowledgment β€” 30 days for remediation of High/Critical findings.