Skip to main content

Security Testing Policy

Security Testing Policy

UpdatedProject 2026-04-29/ for ADR-021 path realignment. See docs/architecture/ADR-021-bilko-blueprint-section-15-realignment.md.

Organization: BilkoALAI Holding ASBalkanDrop AccountingPayment SaaSApp Policy Number: POL-SEC-TEST-001 Version: 1.0 Date: 2026-02-23 Author: CTO / Security EngineerArchitect Status: Draft Reviewers: CISO, Engineering Lead, DPOCTO Next Review: 2027-02-23 Classification: Confidential

Document History

Version Date Author Changes
0.1 2026-02-23 CTOSecurity Architect Initial draft — Drop security testing policy for Bilkomethodology

1. Purpose & Scope

Purpose: This policy defines the security testing requirements,methodology, tools, schedule,frequency, and acceptanceremediation criteriarequirements for all systems operated by ALAI Holding AS for the BilkoDrop platform.payment Bilko handles regulated financial data (tax IDs, IBAN, accounting records) across three jurisdictions.app. Security testing is mandatory,mandatory not optional.no system goes to production without completing applicable security tests.

Regulatory basis:

  • IKT-forskriften (FOR-2003-05-21-630) §§ 5-6 — ICT security verification
  • DORA (EU) 2022/2554 Art. 24-25 — Digital operational resilience testing
  • Finanstilsynet licensing requirements — penetration test before production launch
  • GDPR Art. 32(1)(d) — regular testing of technical measures

Scope:

  • All Bilkoproduction applicationsAPIs and Express APIendpoints (apps/api-express/getdrop.no, api.getdrop.no),
  • Next.js
  • All frontendAWS infrastructure (apps/web/),App databaseRunner, layerS3, (PrismaKMS, +Secrets PostgreSQL),Manager)
  • All CI/CD pipelines and externalbuild systems
  • All third-party integrations (SEF,BankID, HR-FISK).Sumsub, TheOpen Kotlin/KtorBanking backendpartners)
  • Developer workstations handling Confidential or Restricted data

Policy Owner: CISO (apps/api/)[email protected]) isOperational coveredOwner: separatelySecurity asteam it+ maturesEngineering (MC #5125).Lead


2. Security Testing PyramidMethodology

Approach: Shift-left security — testing integrated throughout development, not bolted on at the end.

Testing layers:

graphDevelopment TDPhase
    subgraph+-- AUTOMATED["AutomatedUnit security tests — Vitest (runscurrent: 20+ security-specific tests)
    +-- SCA — npm audit (every commit, automated)
    +-- Secret scanning — detect leaked credentials (every commit)

Build / CI pipeline)"]
        SAST["SAST\nESLint Security Rules\nTypeScript strict mode\nnpm audit\nSnyk SCA"]
        UNIT["Security Unit Tests\nVitest\nRBAC matrix tests\nOrg isolation tests\nEncryption tests\nVAT accuracy tests"]
        INT["Integration Tests\nVitestPhase
    +-- Supertest\nAuthSAST flow tests\nJWTstatic validation\nRatecode limiting tests"]
    end

    subgraph PERIODIC["Periodicanalysis (scheduled)"]every DAST["DAST\nOWASPPR ZAP\nMonthly— planned Phase 2)
    +-- pre-release"]SCA E2E["Security E2E\nPlaywright\nCross-tenantdependency boundaryvulnerability tests\nPrivilege escalation tests"]
    end

    subgraph MANUAL["Manualcheck (scheduled)"]every PENTEST["PR)
    +-- Secret scanning — full scan (every PR)

Deployment Phase
    +-- DAST — OWASP ZAP against staging (planned — Phase 3)
    +-- API security scan — endpoint fuzzing (planned — Phase 3)

Operational Phase
    +-- Vulnerability assessment — external attack surface (quarterly)
    +-- Penetration Test\nExternaltest vendor\nAnnual"] REVIEW["Securitymanual Codeexpert Review\nPre-mergetesting (security-sensitivebefore PRs)\nArchitecturePhase 3 launch)
    +-- Post-incident review quarterly"] endregression UNITtests -->after INTany -->security DAST --> PENTESTincident

3. AutomatedCurrent Security TestingTest (CI/CD)Coverage

Every push to main and every pull request triggers:

3.1 StaticVitest AnalysisUnit (SAST)Security Tests

Status: Implemented — 20+ security-specific tests Source: src/drop-app/src/__tests__/

ToolTest Category What It ChecksTest Failure ThresholdSource
ESLint + eslint-plugin-securityAuthentication CommonJWT JSsecret securityrequired patternsin (eval, RegExp DoS, object injection)production Any errorauth.test.ts level finding blocks merge
TypeScript strict modeAuthentication TypeCookie: safetyhttpOnly=true, preventssecure=true, implicit any that could bypass validationsameSite=strict Build failure blocks mergeauth.test.ts
npm audit --audit-level=highAuthentication KnownJWT vulnerabilitiescontains in dependenciessetIssuedAt() HIGH or CRITICAL CVEs block mergeauth.test.ts
Snyk (optional Phase 2)Authentication DeeperSession revocation: revoked token rejectedauth.test.ts
AuthenticationLogout revokes all user sessionsauth.test.ts
Passwordbcrypt used — not SHA-256utils-server.test.ts
Passwordbcrypt cost factor >= 12utils-server.test.ts
PasswordSHA-256 hash rejected as invalid (fix C4)utils-server.test.ts
Input ValidationIBAN checksum validationvalidation.test.ts
Input ValidationCurrency whitelist enforcedvalidation.test.ts
Input ValidationLanguage whitelist enforcedvalidation.test.ts
Input ValidationAmount: NaN/Infinity rejectedvalidation.test.ts
Input ValidationHTML tags stripped by sanitizeText()validation.test.ts
SQL InjectionParameterized queries for all user inputsdb.test.ts
Rate LimitingAuth rate limit: 10/60s enforcedmiddleware.test.ts
Rate LimitingTransaction rate limit: 10/60s enforcedmiddleware.test.ts
CSRFOrigin header validatedmiddleware.test.ts
CSRFInvalid origin rejectedmiddleware.test.ts
IDORTransaction query scoped to user_idtransactions.test.ts
IDORRecipient query scoped to user_idrecipients.test.ts
Feature FlagsCards endpoint returns 404 when flag disabledfeature-flags.test.ts

3.2 Running the Security Test Suite

# Run all security tests
cd src/drop-app && npx vitest run --reporter verbose

# Run specific security test file
npx vitest run src/__tests__/auth.test.ts

# Run with coverage
npx vitest run --coverage

Blocking criteria: All security tests MUST pass before merge to main branch.


4. Testing Types, Tools & Schedule

4.1 SCA including licenseSoftware complianceComposition Analysis

Status: Implemented (npm audit)

PropertyValue
Tool CRITICALnpm audit (built-in) + GitHub Dependabot (planned)
FrequencyEvery commit (pre-commit hook) + every PR
BlockingYES — Critical CVE blocks merge

3.2

Current Securitydependency Unitsecurity Testsstatus (Vitest)

2026-02-13

Location: apps/api-express/src/__tests__/security/audit):

Required

testsuites:

RBAC

MatrixTests





Everypermissioncombinationexplicitlytesteddescribe('RBACInvoiceaccess',{constroles=['owner','admin',test.each([['owner','create',true],['admin','create',['accountant','create',true],['viewer','create',false],'delete',true],['admin','delete',true],['accountant',failthebuild
Package Version Risk Status
//jose ^6.1.3 Low No mustknown beCVEs
bcryptjs ^3.0.3 Low No ()known =>CVEs
better-sqlite3 ^12.6.2 Low No 'accountant',known 'viewer']CVEs
next 16.1.6 Low Recent true],version
react 19.2.3 Low Latest ['owner',major
radix-ui ^1.4.3 Low UI 'delete', false], ['viewer', 'delete', false], ])('role=%s action=%s expected=%s', async (role, action, expected) => { const token = signTestJWT({ role, org: 'org-1' }) const res = await request(app).post(`/api/invoices`).set('Authorization', `Bearer ${token}`) // check response matches expected }) })

Organization Isolation Tests (Multi-Tenant Critical)

describe('Org isolationonly — no cross-tenant data leak', () => {
  let org1Token: string
  let org2InvoiceId: string

  beforeAll(async () => {
    // Setup two orgs with data
    org1Token = signTestJWT({ org: 'org-1', role: 'owner' })
    const org2Token = signTestJWT({ org: 'org-2', role: 'owner' })

    // Create invoice in org-2
    const res = await request(app)
      .post('/api/invoices')
      .set('Authorization', `Bearer ${org2Token}`)
      .send(validInvoicePayload)
    org2InvoiceId = res.body.id
  })

  test('org-1 cannot read org-2 invoice', async () => {
    const res = await request(app)
      .get(`/api/invoices/${org2InvoiceId}`)
      .set('Authorization', `Bearer ${org1Token}`)
    expect(res.status).toBe(404) // NOT 403 — don't reveal existence
  })

  test('org-1 list does not include org-2 data', async () => {
    const res = await request(app).get('/api/invoices').set('Authorization', `Bearer ${org1Token}`)
    const ids = res.body.data.map((i: any) => i.id)
    expect(ids).not.toContain(org2InvoiceId)
  })
})

Field Encryption Tests

describe('Field encryption — L4 Restricted', () => {
  test('PIB stored encrypted in DB', async () => {
    const testPIB = '123456789' // fake PIB
    // Create contact with PIB
    await request(app)
      .post('/api/contacts')
      .set('Authorization', `Bearer ${ownerToken}`)
      .send({ name: 'Test', taxId: testPIB, type: 'RS' })

    // Read raw DB value — should not be plaintext
    const raw = await prisma.$queryRaw`
      SELECT "taxId" FROM "Contact" WHERE name = 'Test'
    `
    expect(raw[0].taxId).not.toBe(testPIB)
    expect(raw[0].taxId).toMatch(/^[A-Za-z0-9+/]+=*:[A-Za-z0-9+/]+=*:[A-Za-z0-9+/]+=*$/)
    // Should be base64:base64:base64 format (iv:authTag:ciphertext)
  })

  test('decrypted PIB matches original on read', async () => {
    const res = await request(app).get('/api/contacts').set('Authorization', `Bearer ${ownerToken}`)
    const contact = res.body.data.find((c: any) => c.name === 'Test')
    expect(contact.taxId).toBe('123456789')
  })
})

VAT Accuracy Tests (Financial Compliance)

describe('VAT calculation accuracy', () => {
  test('RS: VAT 20% on standard goods (NUMERIC precision)', () => {
    const net = new Decimal('100.00')
    const vatAmount = net.mul('0.20')
    const gross = net.plus(vatAmount)
    expect(vatAmount.toString()).toBe('20.00')
    expect(gross.toString()).toBe('120.00')
  })

  test('HR: VAT 25% (EUR since Jan 2024)', () => {
    const net = new Decimal('100.00')
    const gross = net.mul('1.25')
    expect(gross.toString()).toBe('125.00')
  })

  test('BA: VAT 17% (UIO standard)', () => {
    const net = new Decimal('100.00')
    const gross = net.mul('1.17')
    expect(gross.toString()).toBe('117.00')
  })

  test('No float drift on invoice totals', () => {
    // Known JS float bug: 0.1 + 0.2 !== 0.3
    const line1 = new Decimal('0.10')
    const line2 = new Decimal('0.20')
    expect(line1.plus(line2).toString()).toBe('0.30')
    // Contrast: expect(0.1 + 0.2).toBe(0.3) would FAIL
  })
})

Authentication Tests

describe('Auth — JWT security', () => {
  test('expired access token returns 401', async () => {
    const expiredToken = signTestJWT({ exp: Math.floor(Date.now() / 1000) - 1 })
    const res = await request(app)
      .get('/api/invoices')
      .set('Authorization', `Bearer ${expiredToken}`)
    expect(res.status).toBe(401)
  })

  test('tampered token returns 401', async () => {
    const validToken = signTestJWT({ role: 'viewer' })
    // Tamper: change role claim in payload
    const parts = validToken.split('.')
    const payload = JSON.parse(Buffer.from(parts[1], 'base64url').toString())
    payload.role = 'owner' // attempt privilege escalation
    parts[1] = Buffer.from(JSON.stringify(payload)).toString('base64url')
    const tamperedToken = parts.join('.')
    const res = await request(app)
      .delete('/api/invoices/any-id')
      .set('Authorization', `Bearer ${tamperedToken}`)
    expect(res.status).toBe(401)
  })

  test('rate limiting: 6th auth attempt in 15min returns 429', async () => {
    for (let i = 0; i < 5; i++) {
      await request(app).post('/api/auth/login').send({ email: 'x', password: 'wrong' })
    }
    const res = await request(app).post('/api/auth/login').send({ email: 'x', password: 'wrong' })
    expect(res.status).toBe(429)
  })
})

3.3 Dependency Scanning

# .github/workflows/security.yml
- name: Audit dependencies
  run: npm audit --audit-level=high
  # HIGH or CRITICALknown CVEs
-

Source: name: Check for secrets in code uses: trufflesecurity/trufflehog@main # Scans for committed credentials, API keys ~/ALAI/products/Drop/security/drop-security-rapport.md

Dependency update policy:

  • CRITICALSecurity CVE:patches patch(Critical/High): Merge within 24SLA hours(see §5)
  • HIGHMinor CVE:security patchupdates: Merge within 714 days
  • MEDIUMMajor CVE:updates: patchPlanned migration within 3090 days

Approved licenses: MIT, Apache 2.0, BSD (2-clause, 3-clause), ISC


4.2 SAST — Static Application Security Testing

Status: Planned (Phase 2)

PropertyValue
ToolSemgrep or CodeQL (via GitHub Advanced Security)
FrequencyEvery PR (full scan)
LanguagesTypeScript, JavaScript
BlockingYES — Critical or High findings block merge

SAST rules in scope (when implemented):

  • LOWSQL CVE:injection patchdetection at(parameterized nextqueries sprintvalidation)
  • boundary
  • JWT algorithm confusion (alg: none detection)
  • Hardcoded secrets / credentials
  • Insecure cryptography (MD5, SHA-1, DES, RC4)
  • Path traversal / LFI
  • IDOR patterns (database queries without user_id scoping)
  • Missing authentication middleware

4.3 DAST — Dynamic Application Security Testing (DAST)

OWASP ZAP

Schedule:Status: MonthlyPlanned (Phase 3 — before production launch)

release

Scope

(in-scopefor ZAP):

/api/
  • Authentication
  • flows
  • File
  • PropertyValue
    ToolOWASP ZAP (planned)
    FrequencyEvery deployment to staging + beforeweekly everyfull majorscan
    Target https://staging.bilko.iogetdrop.no (staging environment only — NEVER production)production
  • Allwithout APICISO endpointswritten underapproval
  • Blocking YES upload endpointsdeployment (halted if any)Critical finding discovered

    OutDAST ofscan scope:

    • SEFAll portal,24 FINAAPI portalendpoints (externalauthenticated systems)+ unauthenticated)
    • RailwayAuthentication infrastructureflows (login, registration, logout, session handling)
    • CloudflareRate WAFlimiting (managedverify by10/60s Cloudflare)limits enforced)
    • CSRF protection (Origin header validation)
    • Input validation (IBAN, currency, language, amount)
    • Security headers presence (HSTS, CSP, X-Frame-Options, etc.)
    • SSL/TLS configuration (TLS 1.3, no TLS 1.0/1.1)
    • JWT handling (expiry, algorithm, revocation)
    • Feature flag enforcement (cards endpoints return 404 when disabled)

    4.4 Penetration Testing

    ZAPStatus: Configuration:Required before Phase 3 production launch (Finanstilsynet licensing requirement)

    PropertyValue
    FrequencyBefore production launch + annual thereafter
    ScopeFull application + API + AWS infrastructure
    MethodologyOWASP Testing Guide v4.2 + PTES
    ProviderExternal security firm (not yet selected)
    BlockingCritical findings: system taken offline until remediated

    Penetration test scope:

    # zap-baseline.yaml
    env:
      contexts:In-scope:
    - name:Staging Bilko API
          urls:
            -pre-launch: https://staging.bilko.io/api/getdrop.no
    authentication:- method:Production script(after #launch): ZAPhttps://getdrop.no, scripthttps://api.getdrop.no
    to- authenticateAuthentication flows (login, registration, BankID OIDC callback — Phase 2)
    - All 24 authenticated API endpoints
    - Session management (JWT, cookie handling, revocation)
    - Rate limiting and getCSRF JWT
      rules:protection
    - id:AWS 10202App #Runner Absenceconfiguration
    - Cloudflare WAF configuration
    
    Out-of-scope:
    - Denial of Anti-CSRFservice tokens — note (cookies are httpOnly)
          threshold: LOWattacks
    - id:Social 10096engineering #of Timestampstaff Disclosurewithout prior ignoreapproval
    - AWS infrastructure itself (timestampsAWS areglobal public)responsibility)
    threshold:- OFFBankID Norge AS systems
    - Sumsub systems
    
    Rules of engagement:
    - Testing window: To be agreed in writing with provider
    - Notify before testing: [email protected]
    - Halt on critical finding: Immediately notify [email protected] + CTO
    

    RequiredKey ZAPtest findingsareas thresholdfor (before release):Drop:

      1. CRITICALJWT /manipulation HIGH:(algorithm 0confusion, allowedexpiry bypass, forged tokens)
      2. MEDIUM:Session mustrevocation bebypass assessed(sessions table known acceptable risks documentedmanipulation)
      3. LOWIDOR /attacks INFORMATIONAL:(user_id documentscoping andvalidation prioritizeacross all 24 endpoints)
  • Rate limiting bypass (IP spoofing via X-Forwarded-For)
  • CSRF (Origin header bypass)
  • SQLi in all 24 endpoints (parameterized query verification)
  • BankID OIDC callback manipulation (Phase 2)
  • Feature flag bypass (cards endpoints when disabled)
  • Foedselsnummer exposure (ensure never in plaintext logs or API responses)

  • 5. PenetrationVulnerability Testing

    Frequency: Annual (or after significant architecture change) Provider: External certified pentest firm (OSCP/CREST certified)

    Scope:

    • Web application (app.bilko.io)
    • API endpoints
    • AuthenticationClassification & session management
    • Multi-tenant isolation (primary focus — org isolation must be tested)
    • Business logic flaws (VAT calculation, invoice numbering)
    • Third-party integrations (SEF API, HR-FISK)

    Rules of engagement:

    • Staging environment only — no production testing without explicit CEO approval
    • No DoS / DDoS testing
    • No social engineering of employees
    • Penetration test agreement signed before engagement begins

    Remediation SLAs

    5.1 Severity Classification (post-pentestCVSS findings):

    v3.1)

    hoursdaysdays
    Severity FixCVSS DeadlineScoreDrop-Specific Definition
    CRITICALCritical 489.0-10.0 RCE, auth bypass without credentials, mass PII exfiltration, JWT forgery, foedselsnummer exposure
    HIGHHigh 77.0-8.9 Privilege escalation, IDOR (cross-user data access), auth bypass (authenticated), SQL injection
    MEDIUMMedium 304.0-6.9 CSRF, reflected XSS, rate limit bypass, information disclosure
    LOWLow0.1-3.9Version disclosure, weak error messages, minor misconfigurations
    InformationalN/ABest practice recommendations

    5.2 Remediation SLAs

    SeveritySLAAction on Breach of SLA
    CriticalContainment in 4h; full remediation in 24 hoursEmergency — CISO + CTO + CEO. System taken offline if risk cannot be mitigated.
    High7 calendar daysEscalate to CISO. Engineering Lead must approve extension.
    Medium30 calendar daysEngineering Lead tracks. Exception requires Security team sign-off.
    Low90 calendar daysTracked in backlog. Reviewed in quarterly security review.
    Informational Next quartersprint (best effort)Not SLA-bound.

    SLA tracking: GitHub Issues with label security-finding + severity label.


    6. Security Code Review Checklist

    Required for every PR touching authentication, authorization, payment processing, PII, or cryptography:

    Authentication & Authorization:

    •  No hardcoded credentials, JWT secrets, or API keys
    •  Password hashing uses bcrypt (cost >= 12) — SHA-256 explicitly rejected (fix C4)
    •  JWT validation: signature, expiry, iat claim verified via jose
    •  Session revocation: all protected endpoints check sessions table for revoked = 0
    •  No role flags from user-supplied input
    •  All protected endpoints have authentication middleware applied
    •  Logout revokes sessions server-side (not just clears cookie)

    Input Validation:

    •  All user inputs validated using Drop validators (validateAmount, validateIBAN, validateCurrency, validateLanguage, sanitizeText)
    •  All database operations use parameterized ? queries — no string concatenation
    •  User data queries include AND user_id = ? scoping (IDOR prevention)
    •  No eval(), exec(), or shell command interpolation with user input

    Cryptography:

    •  No MD5, SHA-1, DES, RC4 (per data-encryption-policy.md §2.2)
    •  Random values use crypto.randomBytes() — not Math.random()
    •  IVs/nonces are random (96-bit minimum) and never reused
    •  No cryptographic keys in source code, logs, or error messages

    Error Handling:

    •  No stack traces or internal paths in API error responses
    •  Generic messages for authentication failures (no user enumeration)
    •  Errors logged to Sentry internally but not exposed in API responses

    Data Handling:

    •  Foedselsnummer not logged in plaintext (never in Sentry, BetterStack, console.log)
    •  Sensitive data not in query parameters (use POST body)
    •  Feature flags checked before any cards-related endpoint
    •  AML retention: user data deletion respects 5-year retention (Hvitvaskingsloven § 30)

    Dependencies:

    •  New dependencies reviewed with npm audit before adding
    •  No end-of-life packages introduced
    •  License compatible (MIT, Apache 2.0, BSD, ISC)

    7. Security Testing in CI/CD Pipeline

    Current pipeline (MVP):

    Developer Commit
        +-- Pre-commit hook: npm audit (SCA)
            |
            v
        Git Push -> PR
            |
            v
        Vitest security tests (20+ tests)
            |
            v (all pass)
        Merge to main
            |
            v
        Deploy to AWS App Runner
    

    Target pipeline (Phase 2+):

    flowchart LR
        COMMIT[Developer\nCommit] -->|Pre-commit| SCA_INC[npm audit\nSCA check]
        SCA_INC -->|Pass| PUSH[Git Push]
        PUSH --> PR[Pull Request]
    
        PR --> VITEST[Vitest\nSecurity Tests]
        PR --> SAST[SAST\nSemgrep/CodeQL]
        PR --> SCA_FULL[npm audit\nFull scan]
        PR --> SECRET[Secret\nScanning]
    
        VITEST & SAST & SCA_FULL & SECRET -->|All pass| BUILD[Build\nDrop App]
        BUILD --> STAGING[Deploy to\nStaging]
        STAGING --> DAST[OWASP ZAP\nDAST Scan]
        DAST -->|Pass| GATE{Security\nGate}
    
        GATE -->|Pass| PROD[Deploy to\nProduction]
        GATE -->|Fail| BLOCK[Block Deploy\nAlert [email protected]]
    

    Pipeline security gate criteria:

    GateToolBlocking Criteria
    Pre-commitnpm auditCritical CVE
    PR gate 1Vitest security testsAny test failure
    PR gate 2SAST (Phase 2)Critical or High finding
    PR gate 3npm audit fullCritical CVE
    PR gate 4Secret scanningAny detected secret
    Post-stagingDAST (Phase 3)Critical or High dynamic finding

    6.8. Security CodeAudit ReviewHistory

    DateTypeProviderFindingsStatus
    2026-02-12Full security auditInternal (Security Architect)4C / 5H / 6M / 4LComplete
    2026-02-13Hardening verificationInternal0C / 0H / 2M / 4LComplete
    TBD (Phase 3)External penetration testTBDPlanned — required before launch
    TBD (Phase 3+)Annual pentestTBDAnnual thereafter

    Source: ~/ALAI/products/Drop/security/drop-security-rapport.md

    Security Hardening Summary (2026-02-13)

    FindingIDStatus
    Card data: only last_four + token_ref stored (no PAN/CVV)C1Resolved
    Demo credentials gated behind NODE_ENV !== 'production'C2Resolved
    SHA-256 password support removed — bcrypt onlyC4Resolved
    Session revocation implemented and activeC6/H1Resolved
    Input sanitization applied to all text fieldsH4Resolved
    Notification IDs validated (max 100, format check)M5Resolved
    Settings: currency/language validated against whitelistsM6Resolved

    Remaining items:

    FindingIDTypePlan
    CSP: unsafe-inline/unsafe-eval required by Next.jsM1MediumNonce-based CSP in Phase 3
    Proxy HOSTNAME configM2MediumResolve in Phase 2 AWS config

    9. Reporting Format

    9.1 Individual Finding

    Finding ID: VULN-{YEAR}-{SEQUENCE}
    Title: {SHORT_DESCRIPTION}
    Severity: Critical / High / Medium / Low
    CVSS Score: {SCORE} (v3.1)
    
    Description:
    {DETAILED_DESCRIPTION}
    
    Affected Endpoint / File:
    - {ENDPOINT_OR_FILE}: {URL_OR_LINE_NUMBER}
    
    Proof of Concept:
    {STEPS_TO_REPRODUCE}
    
    Impact:
    {WHAT_AN_ATTACKER_CAN_DO}
    
    GDPR/AML Implications:
    {IF_PERSONAL_DATA_OR_FINANCIAL_DATA_AFFECTED}
    
    Remediation:
    {SPECIFIC_FIX}
    
    Owner: {ASSIGNED_ENGINEER}
    SLA Due Date: {DATE}
    Status: Open / In Progress / Resolved / Accepted Risk
    

    10. Metrics & KPIs

    MetricTargetReporting Frequency
    Critical findings resolved within SLA100%Monthly
    High findings resolved within SLA100%Monthly
    Vitest security test pass rate100% (blocking)Every PR
    MTTR — Critical< 24 hoursPer incident
    MTTR — High< 7 daysMonthly
    Open High+ findings0 at launchMonthly
    Annual penetration test completedYes (before Phase 3)Annual
    npm audit Critical CVEs0 in productionContinuous

    11. Bug Bounty Program

    WhenStatus: requiredPlanned (mandatoryPhase pre-merge)3 — post-launch) Platform: Intigriti or HackerOne

    Responsible disclosure (interim — before bug bounty): Report security vulnerabilities to [email protected].

    • ChangesAcknowledgment: towithin authentication1 orbusiness authorization codeday
    • Changes to encryption utilities (encryptField, decryptField)
    • Changes to Prisma query patterns (potential org isolation bypass)
    • New external API integrations (SEF, FINA, etc.)
    • Changes to RBAC middleware or permission matrices

    Who reviews: CTO or designated Senior Engineer with security background.

    Checklist for security-sensitive PRs:

    •  No secrets or credentials in code or config
    •  All new Prisma queries include organizationId in WHERE clause
    •  New endpoints have RBAC decorator applied
    •  New user inputs validated with Zod schema
    •  L4 Restricted fields encrypted before write, decrypted after read
    •  LoggedAction entry created for all write operations
    •  Rate limiting applied to new auth-adjacent endpoints

    7. CI/CD Security Gates

    flowchart LR
        PR["Pull Request"] --> LINT["ESLint Security\nRules"]
        LINT -->|"PASS"| AUDIT["npm audit\n--audit-level=high"]
        AUDIT -->|"PASS"| TEST["Vitest\nSecurity Test Suite"]
        TEST -->|"PASS"| SECRETS["TruffleHog\nSecret Scan"]
        SECRETS -->|"PASS"| MERGE["Merge Allowed"]
        LINT -->|"FAIL"| BLOCK["PR Blocked"]
        AUDIT -->|"FAIL"| BLOCK
        TEST -->|"FAIL"| BLOCK
        SECRETS -->|"FAIL"| BLOCK
    

    Non-negotiable gates (cannot be bypassed with --no-verify or --force):

    1. ESLint security rules: zero error findings
    2. npm audit: zero HIGH/CRITICAL CVEs
    3. Vitest security tests: 100% pass — especially org isolation and RBAC tests
    4. TypeScript strict: zero type errors

    8. Vulnerability Disclosure

    Process:

    1. Security researchers may report vulnerabilities to [email protected]
    2. Acknowledgment within 24 hours
    3. Investigation and severity assessmentTriage: within 5 business days
    4. RemediationSafe perharbor: SLAresearchers acting in Sectiongood 5faith are protected from legal action
    5. Responsible disclosure: researcher notified when fix is deployed

    Approval

    Role Name SignatureDate DateSignature
    Author CTO / Security EngineerArchitect 2026-02-23
    Reviewer (Engineering Lead)CISO
    ReviewerEngineering (DPO)Lead
    ApproverCTO CEO
    Management