Skip to main content

Security Testing Policy

Security Testing Policy

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

Organization: ALAI Holding ASBilkoDropBalkan PaymentAccounting AppSaaS Policy Number: POL-SEC-TEST-001 Version: 1.0 Date: 2026-02-23 Author: CTO / Security ArchitectEngineer Status: Draft Reviewers: CISO, Engineering Lead, CTO Next Review: 2027-02-23DPO Classification: Confidential

Document History

Version Date Author Changes
0.1 2026-02-23 Security ArchitectCTO Initial draft — Drop security testing methodologypolicy for Bilko

1. Purpose & Scope

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

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 productionBilko APIsapplications — Express API (apps/api-express/), Next.js frontend (apps/web/), database layer (Prisma + PostgreSQL), and endpoints (getdrop.no, api.getdrop.no)
  • All AWS infrastructure (App Runner, S3, KMS, Secrets Manager)
  • All CI/CD pipelines and build systems
  • All third-partyexternal integrations (BankID,SEF, Sumsub,HR-FISK). OpenThe BankingKotlin/Ktor partners)
  • Developer workstations handling Confidential or Restricted data

Policy Owner: CISObackend ([email protected])apps/api/) Operationalis Owner:covered Securityseparately teamas +it Engineeringmatures Lead(MC #5125).


2. Security Testing MethodologyPyramid

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

Testing layers:

Developmentgraph PhaseTD
    +--subgraph AUTOMATED["Automated (runs every CI pipeline)"]
        SAST["SAST\nESLint Security Rules\nTypeScript strict mode\nnpm audit\nSnyk SCA"]
        UNIT["Security Unit securityTests\nVitest\nRBAC testsmatrix tests\nOrg Vitestisolation tests\nEncryption tests\nVAT accuracy tests"]
        INT["Integration Tests\nVitest + Supertest\nAuth flow tests\nJWT validation\nRate limiting tests"]
    end

    subgraph PERIODIC["Periodic (current:scheduled)"]
        20+DAST["DAST\nOWASP security-specific tests)ZAP\nMonthly + pre-release"]
        E2E["Security E2E\nPlaywright\nCross-tenant boundary tests\nPrivilege escalation tests"]
    end

    subgraph MANUAL["Manual (scheduled)"]
        PENTEST["Penetration Test\nExternal vendor\nAnnual"]
        REVIEW["Security Code Review\nPre-merge (security-sensitive PRs)\nArchitecture review quarterly"]
    end

    UNIT --> SCAINT — npm audit (every commit, automated)
    +-- Secret scanning — detect leaked credentials (every commit)

Build / CI Phase
    +-- SAST — static code analysis (every PR — planned Phase 2)
    +-- SCA — dependency vulnerability check (every 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 — manual expert testing (before Phase 3 launch)
    +-- Post-incident review — regression tests after any security incidentPENTEST

3. CurrentAutomated Security TestTesting Coverage(CI/CD)

Every push to main and every pull request triggers:

3.1 VitestStatic UnitAnalysis Security Tests(SAST)

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

CRITICALblocks
Test CategoryTool TestWhat It Checks SourceFailure Threshold
AuthenticationESLint + eslint-plugin-security JWTCommon secretJS requiredsecurity inpatterns production(eval, RegExp DoS, object injection) Any auth.test.tserror level finding blocks merge
AuthenticationTypeScript strict mode Cookie:Type httpOnly=true,safety secure=true,prevents sameSite=strictimplicit any that could bypass validation auth.test.tsBuild failure blocks merge
Authenticationnpm audit --audit-level=high JWTKnown containsvulnerabilities setIssuedAt()in dependencies auth.test.tsHIGH or CRITICAL CVEs block merge
AuthenticationSnyk (optional Phase 2) SessionDeeper revocation:SCA revokedincluding tokenlicense rejectedcompliance auth.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.tsmerge

3.2 Running the Security TestUnit SuiteTests (Vitest)

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

Required test suites:

RBAC Matrix Tests

// Every permission combination must be explicitly tested
describe('RBAC — Invoice access', () => {
  const roles = ['owner', 'admin', 'accountant', 'viewer']

  test.each([
    ['owner', 'create', true],
    ['admin', 'create', true],
    ['accountant', 'create', true],
    ['viewer', 'create', false],
    ['owner', 'delete', true],
    ['admin', 'delete', true],
    ['accountant', '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 isolation — 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

# Run.github/workflows/security.yml
all- securityname: testsAudit cddependencies
  src/drop-apprun: &&npm npx vitest runaudit --reporter verboseaudit-level=high
  # RunHIGH specificor securityCRITICAL testCVEs filefail npxthe vitestbuild

run- src/__tests__/auth.test.tsname: Check for secrets in code
  uses: trufflesecurity/trufflehog@main
  # RunScans withfor coveragecommitted npxcredentials, vitestAPI run --coveragekeys

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


4. Testing Types, Tools & Schedule

4.1 SCA — Software Composition Analysis

Status: Implemented (npm audit)

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

Current dependency security status (2026-02-13 audit):

PackageVersionRiskStatus
jose^6.1.3LowNo known CVEs
bcryptjs^3.0.3LowNo known CVEs
better-sqlite3^12.6.2LowNo known CVEs
next16.1.6LowRecent version
react19.2.3LowLatest major
radix-ui^1.4.3LowUI only — no known CVEs

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

Dependency update policy:

  • SecurityCRITICAL patchesCVE: (Critical/High): Mergepatch within SLA24 (see §5)hours
  • MinorHIGH securityCVE: updates: Mergepatch within 147 days
  • MajorMEDIUM updates:CVE: Planned migrationpatch within 9030 days
  • LOW

    ApprovedCVE: licenses:patch MIT,at Apachenext 2.0,sprint 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):

    • SQL injection detection (parameterized queries validation)
    • 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 middlewareboundary

    4.3 DAST — Dynamic Application Security Testing (DAST)

    OWASP ZAP

    Status:Schedule: PlannedMonthly (Phase 3 —+ before productionevery launch)major release

    in-scopeforZAP):

    under/api/
  • Authentication
  • flows
    PropertyValue
    ToolOWASP ZAP

    Scope (planned)

    FrequencyEvery deployment to staging + weekly full scan
    Target
  • https://staging.getdrop.nobilko.io (staging environment only — NEVER productionproduction)
  • without
  • All CISOAPI writtenendpoints approval
  • Blocking YES
  • File upload deploymentendpoints halted (if Criticalany)
  • finding discovered

    DASTOut scanof scope:

    • AllSEF 24portal, FINA portal (external systems)
    • Railway infrastructure
    • Cloudflare WAF (managed by Cloudflare)

    ZAP Configuration:

    # zap-baseline.yaml
    env:
      contexts:
        - name: Bilko API
          endpointsurls:
            - https://staging.bilko.io/api/
          authentication:
            method: script
            # ZAP script to authenticate and get JWT
      rules:
        - id: 10202 # Absence of Anti-CSRF tokens — note (authenticatedcookies +are unauthenticated)httpOnly)
          threshold: LOW
        - id: 10096 # Timestamp Disclosure — ignore (timestamps are public)
          threshold: OFF
    

    Required ZAP findings threshold (before release):

    • CRITICAL / HIGH: 0 allowed
    • AuthenticationMEDIUM: flowsmust (login,be registration,assessed logout, sessionknown handling)acceptable risks documented
    • RateLOW limiting/ (verifyINFORMATIONAL: 10/60sdocument limitsand 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)prioritize

    4.4

    5. Penetration Testing

    Status:Frequency: Required before Phase 3 production launchAnnual (Finanstilsynetor licensingafter requirement)

    significant architecturechange)Provider:
    PropertyValue
    FrequencyBefore production launch + annual thereafter
    ScopeFull application + API + AWS infrastructure
    MethodologyOWASP Testing Guide v4.2 + PTES
    ProviderExternal securitycertified pentest firm (notOSCP/CREST yet selected)
    BlockingCritical findings: system taken offline until remediated
    certified)

    Penetration test scope:Scope:

    In-scope:
      -
    • Web Staging pre-launch: https://staging.getdrop.no - Productionapplication (afterapp.bilko.io)
    • launch):
    • API https://getdrop.no,endpoints
    • https://api.getdrop.no -
    • Authentication flows& session management
    • Multi-tenant isolation (login,primary registration, BankID OIDC callbackfocusPhaseorg 2)isolation -must Allbe 24tested)
    • authenticated
    • Business APIlogic endpoints - Session managementflaws (JWT,VAT cookiecalculation, handling,invoice revocation)numbering)
    • -
    • Third-party Rateintegrations limiting(SEF andAPI, CSRFHR-FISK)
    • protection
    - AWS App Runner configuration - Cloudflare WAF configuration Out-of-scope: - Denial

    Rules of serviceengagement:

    attacks
      -
    • Staging Socialenvironment only — no production testing without explicit CEO approval
    • No DoS / DDoS testing
    • No social engineering of staffemployees
    • without
    • Penetration priortest approvalagreement - AWS infrastructure itself (AWS global responsibility) - BankID Norge AS systems - Sumsub systems Rules of engagement: - Testing window: To be agreed in writing with provider - Notifysigned before testing:engagement [email protected]begins
    • - Halt on critical finding: Immediately notify [email protected] + CTO

    Key test areas for Drop:

    1. JWT manipulation (algorithm confusion, expiry bypass, forged tokens)
    2. Session revocation bypass (sessions table manipulation)
    3. IDOR attacks (user_id scoping validation across all 24 endpoints)
    4. Rate limiting bypass (IP spoofing via X-Forwarded-For)
    5. CSRF (Origin header bypass)
    6. SQLi in all 24 endpoints (parameterized query verification)
    7. BankID OIDC callback manipulation (Phase 2)
    8. Feature flag bypass (cards endpoints when disabled)
    9. Foedselsnummer exposure (ensure never in plaintext logs or API responses)

    5. Vulnerability Classification & Remediation SLAs

    5.1 Severity Classification (CVSSpost-pentest v3.1)

    findings):

    48730Next
    Severity CVSSFix ScoreDrop-Specific DefinitionDeadline
    CriticalCRITICAL 9.0-10.0 RCE, auth bypass without credentials, mass PII exfiltration, JWT forgery, foedselsnummer exposurehours
    HighHIGH 7.0-8.9 Privilege escalation, IDOR (cross-user data access), auth bypass (authenticated), SQL injectiondays
    MediumMEDIUM 4.0-6.9 CSRF, reflected XSS, rate limit bypass, information disclosuredays
    LowLOW 0.1-3.9 Version disclosure, weak error messages, minor misconfigurations
    InformationalN/ABest practice recommendationsquarter

    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.
    InformationalNext sprint (best effort)Not SLA-bound.

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


    6. Security Code Review Checklist

    RequiredWhen forrequired every(mandatory PRpre-merge):

    touching
      authentication,
    • Changes authorization,to payment processing, PII,authentication or cryptography:authorization code
    • 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.

    AuthenticationChecklist &for Authorization:security-sensitive PRs:

    • No hardcoded credentials, JWT secrets,secrets or APIcredentials keys
    • in
    • code Passwordor 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 inputconfig
    • All protectednew Prisma queries include organizationId in WHERE clause
    •  New endpoints have authenticationRBAC middlewaredecorator applied
    • Logout revokes sessions server-side (not just clears cookie)

    Input Validation:

    •  AllNew user inputs validated usingwith DropZod validators (validateAmount, validateIBAN, validateCurrency, validateLanguage, sanitizeText)schema
    • AllL4 databaseRestricted operationsfields useencrypted parameterizedbefore ?write, queriesdecrypted after no string concatenationread
    • UserLoggedAction dataentry queriescreated includefor ANDall user_idwrite = ? scoping (IDOR prevention)operations
    • NoRate eval(),limiting 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 loggedapplied to Sentrynew internallyauth-adjacent 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)endpoints

    7. Security Testing in CI/CD PipelineSecurity Gates

    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]PR["Pull Request"] --> LINT["ESLint Security\nRules"]
        LINT -->|Pre-commit|"PASS"| SCA_INC[AUDIT["npm audit\nSCAn--audit-level=high"]
        check]
        SCA_INCAUDIT -->|Pass|"PASS"| PUSH[Git Push]
        PUSH --> PR[Pull Request]
    
        PR --> VITEST[TEST["Vitest\nSecurity Tests]Test PRSuite"]
        --> SAST[SAST\nSemgrep/CodeQL]
        PR --> SCA_FULL[npm audit\nFull scan]
        PR --> SECRET[Secret\nScanning]
    
        VITEST & SAST & SCA_FULL & SECRETTEST -->|All"PASS"| pass|SECRETS["TruffleHog\nSecret BUILD[Build\nDropScan"]
        App]
        BUILD --> STAGING[Deploy to\nStaging]
        STAGING --> DAST[OWASP ZAP\nDAST Scan]
        DASTSECRETS -->|Pass|"PASS"| GATE{Security\nGate}MERGE["Merge GATEAllowed"]
        LINT -->|Pass|"FAIL"| PROD[DeployBLOCK["PR to\nProduction]Blocked"]
        GATEAUDIT -->|Fail|"FAIL"| BLOCK[BlockBLOCK
        Deploy\nAlertTEST [email protected]]-->|"FAIL"| BLOCK
        SECRETS -->|"FAIL"| BLOCK
    

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

    1. ESLint security gaterules: criteria:

      zero errorfindings audit:HIGH/CRITICALCVEs zerotypeerrors
      GateToolBlocking Criteria
      Pre-commit
    2. npm audit
    3. Criticalzero CVE
      PR gate 1
    4. Vitest security tests: 100% pass — especially org isolation and RBAC tests
    5. Any
    6. TypeScript teststrict: failure
    7. 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

    8. SecurityVulnerability Audit History

    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 ProgramDisclosure

    Status:Process: Planned (Phase 3 — post-launch) Platform: Intigriti or HackerOne

    Responsible

      disclosure
    1. Security (interimresearchers may before bug bounty): Report securityreport vulnerabilities to [email protected].

        [email protected]
      • Acknowledgment:Acknowledgment within 124 business dayhours
      • Triage:Investigation and severity assessment within 5 business days
      • SafeRemediation harbor:per researchers actingSLA in goodSection faith are protected from legal action5
    2. Responsible disclosure: researcher notified when fix is deployed

    Approval

    Role Name DateSignature SignatureDate
    Author CTO / Security ArchitectEngineer 2026-02-23
    CISOReviewer (Engineering Lead)
    EngineeringReviewer Lead(DPO)
    CTOApprover
    ManagementCEO