Case study 12 / 19
CSIRT Nusantara Regas Public Website
Public website of the company's Computer Security Incident Response Team: incident reporting guidance, RFC 2350 documents, PGP public key and the BSSN guide library, built as a hardened static Angular 22 site with no backend to attack.
- Stack
- Angular 22 · TypeScript · SCSS · Vitest · Nginx · Docker · CSP · TLS
- Links
- Live Site
The problem
A CSIRT needs a public, trustworthy front door: how to report an incident, which channels are official, the team's RFC 2350 description and its PGP key. For a security team the site itself must not become an attack surface: no forms to abuse, no server-side code to exploit, and headers that hold up under scrutiny.
What I built
I built the site as a static Angular 22 single-page application with standalone components, signals and lazy routes, served by an unprivileged nginx container. Incident reports go by email, optionally PGP-encrypted, so there is no backend and nothing is stored. The production stack adds an edge nginx with TLS, HSTS, request and connection rate limits, GET and HEAD only, a read-only root filesystem, dropped capabilities and an internal network between edge and app. Content lives in typed configuration files: services, reporting steps, incident types, the guide library and the organisation's contact details.
In use
Architecture
Visitors hit a rate-limited edge nginx that terminates TLS and forwards only GET and HEAD to an unprivileged nginx serving the static Angular bundle with CSP headers. There is no backend: incident reports travel by email, the threat map is embedded from its provider, and the documents are static assets copied at build time.
Open the image for full size
Proof
- 01 Angular 22 zoneless application with OnPush components, signal inputs and native control flow; production builds enforce bundle budgets of 500 kB warning and 1 MB error.
- 02 CSP and security headers included from every nginx location, SPA fallback, gzip, cache rules and a health endpoint; the app container runs nginx-unprivileged on Alpine.
- 03 Production Compose with an edge proxy: TLS and HSTS, limit_req and limit_conn per address, only GET and HEAD forwarded, read-only rootfs and cap_drop ALL on both containers.
- 04 Accessibility built in: skip link, aria attributes on navigation, visible focus styles, aria-current on active links, and a responsive menu that turns child links into a dropdown or an accordion.
- 05 Legacy routes redirect to their new homes, every page sets its own title, and the embedded live threat map falls back to a link-out when the provider blocks framing.
Result
The CSIRT has a single public reference for reporting and verification that can be audited line by line: a static bundle, two nginx configurations and no runtime secrets. It is deployed at csirt.nusantararegas.com ahead of its public announcement.