Darkwood · Security Engineering · Darkwaar40

Holding
the Core

Security Engineering Through Darkwaar40 — Breach

Darkwood technical session · @matyo91
01 · Holding the Core · 20–25 min @matyo91

Act I · The game

100 Seconds to Survive

3portals
Autoscan
100integrity
6s+seals
4patch lines
100sobjective

Move, contain the portals, and let Auto-Scan clear nearby threats before they reach the Core.

Darkwaar40 gameplay showing three breach portals around the central Core
02 · Implemented game loop · Real gameplay capture @matyo91

The thesis

Security is not a wall.

Reduce
exposure
Detect
activity
Respond
under pressure
Maintain
resilience

Security is continuous operational work—not a perimeter completed once.

03 · Continuous process @matyo91

The security model

A readable metaphor—with boundaries

Portals→Attack surface Auto-Scan→Detection and triage Temporary seals→Containment Patch choices→Remediation investments Core Integrity→Integrity + availability Enemy pressure→Evolving threats

Not equivalence: a game condenses uncertainty, people, data loss, and recovery into legible decisions.

04 · Metaphor ≠ implementation @matyo91

Act II · Defensive security

Detection is not prevention.

Preventive

Validation, least privilege, patching, and network restrictions constrain what can happen.

Detective

Logs, metrics, traces, anomaly signals, and alerts reveal what may already be happening.

Observe
→
Identify
→
Triage
→
Contain
→
Remediate
→
Verify
→
Learn
05 · Evidence needs ownership · OWASP Logging Cheat Sheet @matyo91

Exposure

Every open portal is an attack surface.

Public APIs
Credentials
Dependencies
Workers
Admin paths
Infrastructure
CORE
Public
API
Supply
chain
Identity
edge
06 · Reachability creates opportunity @matyo91

Attack-surface management

Reduce exposure.

Before · unknown + broad

/admin/debug/v1/v2old-workerCI tokenroot DBunused package
→

After · known + necessary

/v2scoped workerleast-privilege DBrotated secret

Fewer entry points. Smaller blast radius. Clear ownership.

07 · Remove · narrow · inventory @matyo91

Patching under pressure

Four investments. One limited choice.

FirewallWider shield, longer seals, farther sealing reach.Containment
Scan RateFaster, stronger, longer-range automatic scanning.Detection + response
QuarantinePeriodic slow applied to threats near the player.Control
MendRestore Core Integrity and briefly regenerate it.Recovery
Darkwaar40 Patch choice interface

Game upgrade ≠ software patch. Real remediation changes code or configuration, then requires testing, deployment, rollback, and verification.

08 · Competing defensive investments @matyo91

21 October 2026 · PHP security release

A patch is a coordinated response.

2critical remote-code-execution vulnerabilities

Discovery → triage → coordination → fix → packaging → communication → deployment

Fixed versions cited by CERT-FR

PHP 8.2.35
PHP 8.3.36
PHP 8.4.27
PHP 8.5.12

Sources: CERTFR-2026-ALE-014 · The PHP Foundation

The exposure window closes only when the fix is deployed and verified.

09 · Verified advisory data @matyo91

Vulnerability prioritization

Severity alone is not the queue.

Severity
×
Exploitability
×
Exposure
×
Business
impact

A conceptual model—not a universal numerical formula. Add existing exploitation, controls, remediation cost, and cost of delay.

10 · Risk-informed ordering · OWASP Risk Rating Methodology @matyo91

Defense in depth

Different layers. Different failures.

Network + TLSLimit reachability and protect transport
AuthenticationEstablish an identity
AuthorizationDecide access to this action and object
Input + interpretationValidate, bind, encode
Monitoring + responseSee and contain control failures
RecoveryRestore trusted service and data

Layering reduces the chance that one defect becomes total compromise.

11 · Before · during · after @matyo91

Act III · PHP + Symfony

Security starts with maintenance.

Dependency signal

composer validate --strict
composer audit --locked
composer outdated --direct

Supported runtime

Track the PHP support calendar and ship security patch releases.

Maintained framework

Know Symfony support dates before the branch becomes an emergency.

Continuous audit

Run Composer audit in CI and on a schedule—not from memory.

Sources: php.net/supported-versions.php · symfony.com/releases · getcomposer.org/doc/03-cli.md#audit

12 · Dependency lifecycle @matyo91

Symfony security baseline

Secure defaults still need explicit policy.

security.yaml

security:
  password_hashers:
    App\Entity\User: 'auto'

  firewalls:
    main:
      lazy: true
      login_throttling:
        max_attempts: 5
        interval: '1 minute'

framework.yaml

framework:
  csrf_protection: true
  session:
    cookie_secure: true
    cookie_httponly: true
    cookie_samesite: lax

Application throttling raises brute-force cost. DDoS protection belongs at a cheaper edge.

13 · Passwords · throttling · CSRF · sessions @matyo91

Identity is not permission

Authentication ≠ authorization

Authentication

Who is presenting this request?

  • Password or identity provider
  • Session or access token
  • Credential validation
→

Authorization

May this identity act on this object?

  • Route and role gates
  • Object-level Symfony voters
  • Ownership and business policy

#[IsGranted('PROJECT_DELETE', 'project')] checks the action against the actual project—not only the login state.

14 · Identity → policy → object @matyo91

Safe input and data handling

Untrusted data must not become instructions.

Doctrine · bind values

$projects = $repository->createQueryBuilder('p')
    ->andWhere('p.owner = :owner')
    ->setParameter('owner', $user)
    ->getQuery()
    ->getResult();

Dynamic identifiers still require an allowlist.

Twig

Keep contextual auto-escaping. Audit every |raw.

Secrets

Use a deployment manager or Symfony vault; keep keys separate.

Logs

Exclude passwords, session IDs, access tokens, and private keys.

Deploy

Production mode, least privilege, narrow web root, tested headers.

15 · Bind · encode · allowlist · redact @matyo91

Act IV · Darkwood Identity

Why replace custom SSO?

Custom protocol

  • Locally designed redirect rules
  • Custom token semantics
  • Private key-rotation behavior
  • Application-specific testing surface
  • Long-term maintenance ownership
→

OpenID Connect

  • Authorization Code flow
  • PKCE S256, state, nonce
  • Discovery and JWKS
  • Standard token claims
  • Interoperable libraries and tooling

Standards do not remove security work. They make the required work explicit and reviewable.

16 · Reduce custom authentication behavior @matyo91

OIDC Authorization Code + PKCE S256

Redirect briefly. Validate rigorously.

User
browser
1 Open Navi admin login
Darkwood
Identity
2 Navi creates state, nonce, verifier + S256 challenge → authorize redirect
3 Login + 2FA at Identity
4 Redirect authorization code + state to Navi
5 Navi exchanges code + original verifier at token endpoint
6 Identity returns signed ID token
7 Navi loads JWKS; validates signature, claims, state + nonce
8 Migrate session ID; apply local admin authorization
9 Local Navi session continues
17 · Code is short-lived; verifier never travels in the authorization request @matyo91

Trust, tokens and sessions

Parsing a JWT is not validation.

issExpected identity provider
aud / azpToken intended for this client
JWKS + RS256Trusted key and valid signature
exp / iatAcceptable lifetime and issue time
nonceID token belongs to this login
stateAuthorization response belongs to this browser flow
sub = UUIDStable subject; email remains a claim
local sessionNavi owns authorization and session policy

OIDC authenticates identity claims. Navi still decides who may administer Navi.

18 · Authentication ≠ application authorization @matyo91

Actual repository state · inspected 24 Oct 2026

Implemented now. Target next.

Implemented in source

  • Darkwood OIDC discovery, authorize, token, JWKS, end-session routes
  • Authorization Code; implicit and password grants disabled
  • Navi PKCE S256, state, nonce, JWKS cache + retry
  • RS256 and claim validation
  • Local role gate and session migration
→

Target architecture

  • Move Navi onto a maintained Symfony branch
  • Adopt Symfony 8.2 native oidc_login
  • Delete more custom relying-party code
  • Preserve local authorization policy

Planned in repository design documentation; Symfony 8.2 was still under development.

Repository code confirms implementation—not deployed production rollout or a completed live login.

19 · Current implementation vs future plan @matyo91

Act V · Limits

What the game gets wrong

Confidentiality is quiet

Data can be copied while the Core still reads 100.

A zero-day is not “stronger”

It is defined by defenders lacking an available fix—not by hit points.

Recovery is not HP

It needs tested backups, rebuilt credentials, restoration, and forensic confidence.

Attackers do not follow timers

They adapt to controls, defenders, incentives, and opportunity.

20 · Keep the decision structure—not the literal model @matyo91

The durable lesson

Security is a continuous loop.

01  Inventory
02  Prevent
03  Detect
04  Respond
05  Recover
06  Improve

The system changes. The threat changes. The loop must keep moving.

21 · Operate the loop @matyo91

Play Darkwaar40 — Breach

Keep moving.
Keep the Core alive.

22 · Holding the Core · Thank you @matyo91