Security Incident Timeline
blocksecuritySecurity Operations Center (SOC) incident response timeline and post-mortem tracker with telemetry KPIs, chronological audit trail, log snippets, and corrective action items.
Installation
$pnpm dlx uipkge-ng@latest add security-incident-timeline$npx uipkge-ng@latest add security-incident-timeline$yarn dlx uipkge-ng@latest add security-incident-timeline$bunx uipkge-ng@latest add security-incident-timelineManifest:
https://uipkge.dev/r/angular/security-incident-timeline.jsonInstalls to:src/app/components/blocks/security-incident-timeline/Variants
Loading interactive previews…
Loading interactive previews…
Files installed (2)
src/app/components/blocks/security-incident-timeline/security-incident-timeline.component.ts46.5 kB
// Security Operations Center (SOC) incident response timeline and post-mortem // tracker: telemetry KPIs, chronological audit trail with log snippets, and // corrective action items. Port of the React block 1:1. import { ChangeDetectionStrategy, Component, Input, signal } from '@angular/core' import { Check, CheckCircle2, Clock, Copy, FileCheck, FileDown, GitPullRequest, KeyRound, Lock, LucideAngularModule, Plus, Radio, Server, Shield, ShieldAlert, ShieldCheck, Terminal, Users, Zap, } from 'lucide-angular' import { cn } from '@/lib/utils' import { UiAvatarComponent, UiAvatarFallbackComponent, UiAvatarImageComponent } from '@/ui/avatar/avatar.component' import { UiBadgeComponent } from '@/ui/badge/badge.component' import { UiButtonComponent } from '@/ui/button/button.component' import { UiCardComponent, UiCardContentComponent, UiCardDescriptionComponent, UiCardHeaderComponent, UiCardTitleComponent, } from '@/ui/card/card.component' import { UiCheckboxComponent } from '@/ui/checkbox/checkbox.component' import { UiSeparatorComponent } from '@/ui/separator/separator.component' const logSnippets: Record<string, string> = { detection: `[2026-08-21T14:12:08.104Z] GUARDDUTY_ALERT: UnauthorizedAccess:IAMUser/InstanceCredentialExfiltration.OutsideAWS PrincipalId: AROA4491X0921:github-worker-ephemeral-tok_88f9x RequestedRole: arn:aws:iam::102938475612:role/SuperAdminPolicy SourceIP: 198.51.100.42 (Tor Exit Node AS13335) | UserAgent: aws-cli/2.15.30 Python/3.11.8 RiskScore: 98/100 | FindingId: gd-find-8891-c0a1-992a | Action: STS:AssumeRoleWithWebIdentity`, triage: `[2026-08-21T14:15:30.412Z] INCIDENT_WAR_ROOM_ESTABLISHED: bridge_id=bridge_sec_0842 IncidentCommander: [email protected] | Responders: [m.vance, d.okoye, j.chen] VectorAnalysis: Ephemeral token tok_88f9x generated in GH Actions workflow run #1049281. ScopeAssessment: Ingress proxy read cache queried; zero write or database mutation detected. EscalationLevel: SEV-1 (Paging IAM + Platform on-call)`, containment: `[2026-08-21T14:22:15.890Z] CLOUDFLARE_WAF_ENFORCED: rule_id=sec_block_tor_asn_13335 action=BLOCK GatewaysSynced: [apigw-iad-prod-01, apigw-iad-prod-02, apigw-iad-prod-03] (3/3 nodes OK) ActiveConnectionsDropped: 14 concurrent TCP streams | RateLimit: 0 req/sec allowed from source EgressQuarantine: ALL external routes from adversary subnet blackholed.`, revocation: `[2026-08-21T14:30:53.002Z] VAULT_REVOCATION_BROADCAST: lease_prefix=auth/token/tok_88f9x leases_revoked=38 KMS_KEY_ROTATED: arn:aws:kms:us-east-1:102938475612:key/cmk-gateway-signing-02 -> key_version_v3 RedisClusterBroadcast: AUTH_CACHE_PURGE_SUCCESS (12/12 shards synchronized in 84ms) TokenVerificationState: REVOCATION_COMPLETE (0 surviving tokens)`, postmortem: `[2026-08-21T14:48:00.651Z] SOC_AUDIT_SWEEP: duration=15m00s | unauthorized_calls=0 | perimeter_status=NOMINAL IncidentStatusTransition: SEV-1_ACTIVE -> MITIGATED_POST_MORTEM ForensicsArchive: s3://sec-incident-vault-us-east-1/incidents/2026-0842/evidence_bundle.tar.gz.enc EvidenceSignOff: [m.vance, e.rostova] | Hash: sha256:7f83b1657ff1fc53b92dc18148a1d65`, } @Component({ changeDetection: ChangeDetectionStrategy.Eager, selector: 'ui-security-incident-timeline, [ui-security-incident-timeline]', standalone: true, // React renders the root <div> itself: the host stays out of layout and `class` goes to the root. host: { '[attr.class]': '"contents"' }, imports: [ LucideAngularModule, UiAvatarComponent, UiAvatarFallbackComponent, UiAvatarImageComponent, UiBadgeComponent, UiButtonComponent, UiCardComponent, UiCardContentComponent, UiCardDescriptionComponent, UiCardHeaderComponent, UiCardTitleComponent, UiCheckboxComponent, UiSeparatorComponent, ], template: ` <div data-slot="security-incident-timeline" [class]="rootClass"> <!-- 1. Incident Header Card --> <div ui-card class="border-border shadow-xs"> <div ui-card-header class="space-y-4"> <div class="flex flex-col gap-4 lg:flex-row lg:items-start lg:justify-between"> <div class="space-y-2"> <!-- Badge Metadata Bar --> <div class="flex flex-wrap items-center gap-2"> <span ui-badge variant="outline" class="font-mono text-xs font-semibold tracking-wider"> {{ incidentId }} </span> <!-- Severity Badge with Pulsing Red Dot --> <span ui-badge variant="destructive" class="gap-1.5 font-mono text-xs font-semibold uppercase"> <span class="relative flex size-2 shrink-0"> <span class="bg-destructive absolute inline-flex h-full w-full rounded-full opacity-75"></span> <span class="relative inline-flex size-2 rounded-full bg-white"></span> </span> {{ severity }} </span> <!-- Status Badge --> @if (!isResolved()) { <span ui-badge variant="warning" class="gap-1.5 font-mono text-xs font-semibold"> <span class="bg-warning size-2 rounded-full"></span> {{ status }} </span> } @else { <span ui-badge variant="success" class="gap-1.5 font-mono text-xs font-semibold"> <span class="bg-success size-2 rounded-full"></span> Resolved · Closed </span> } <span class="text-muted-foreground text-xs font-medium"> Region: <span class="text-foreground font-mono">us-east-1 (N. Virginia)</span> </span> </div> <!-- Title & Description --> <div class="space-y-1"> <h1 class="text-foreground text-2xl font-bold tracking-tight sm:text-3xl"> {{ incidentTitle }} </h1> <p class="text-muted-foreground text-sm"> Adversarial AWS STS role assumption anomaly flagged across external ingress gateways. Compromised ephemeral CI/CD workflow token quarantined and revoked in 18 minutes. </p> </div> </div> <!-- Action Buttons --> <div class="flex flex-wrap items-center gap-2"> <button ui-button aria-label="Dismiss notification" variant="outline" size="sm" class="h-9 gap-1.5 text-xs" (click)="handleExportPdf()" > @if (exportNotification()) { <lucide-icon [img]="Check" class="text-success size-3.5" aria-hidden="true" /> } @else { <lucide-icon [img]="FileDown" class="size-3.5" aria-hidden="true" /> } <span>{{ exportNotification() ? 'Exporting PDF...' : 'Export Incident Report PDF' }}</span> </button> <button ui-button variant="outline" size="sm" class="h-9 gap-1.5 text-xs" (click)="handleAddUpdate()"> @if (updateAddedNotification()) { <lucide-icon [img]="Check" class="text-success size-3.5" aria-hidden="true" /> } @else { <lucide-icon [img]="Plus" class="size-3.5" aria-hidden="true" /> } <span>{{ updateAddedNotification() ? 'Draft Created' : 'Add Timeline Update' }}</span> </button> <button ui-button [variant]="isResolved() ? 'outline' : 'default'" size="sm" class="h-9 gap-1.5 text-xs font-medium" (click)="handleResolve()" > <lucide-icon [img]="ShieldCheck" class="size-3.5" aria-hidden="true" /> <span>{{ isResolved() ? 'Re-open Incident' : 'Resolve Incident' }}</span> </button> </div> </div> <ui-separator /> <!-- Commander & Forensics Meta Strip --> <div class="grid grid-cols-1 gap-4 text-xs sm:grid-cols-2 lg:grid-cols-4"> <div class="flex items-center gap-3"> <ui-avatar class="size-9 border"> <ui-avatar-image src="https://i.pravatar.cc/72?img=60" alt="Marcus Vance" /> <ui-avatar-fallback class="bg-primary/10 text-primary font-semibold">MV</ui-avatar-fallback> </ui-avatar> <div class="min-w-0"> <p class="text-muted-foreground text-xs font-medium">Incident Commander</p> <p class="text-foreground truncate text-sm font-semibold">{{ commanderName }}</p> <p class="text-muted-foreground truncate text-xs">{{ commanderRole }}</p> </div> </div> <div class="space-y-1"> <p class="text-muted-foreground text-xs font-medium">Detection Trigger</p> <p class="text-foreground font-mono text-xs font-semibold">GuardDuty · IAM.Anomaly.STS</p> <p class="text-muted-foreground text-xs">2026-08-21 14:12:08 UTC</p> </div> <div class="space-y-1"> <p class="text-muted-foreground text-xs font-medium">Threat Vector & Origin</p> <p class="text-foreground font-mono text-xs font-semibold">198.51.100.42 (Tor Exit Node)</p> <p class="text-muted-foreground text-xs">AS13335 · Ephemeral OIDC Leak</p> </div> <div class="space-y-1"> <p class="text-muted-foreground text-xs font-medium">Incident War Room</p> <div class="flex items-center gap-2"> <span class="relative flex size-2 shrink-0"> <span class="bg-success absolute inline-flex h-full w-full rounded-full opacity-75"></span> <span class="bg-success relative inline-flex size-2 rounded-full"></span> </span> <p class="text-foreground font-mono text-xs font-semibold">#bridge-sec-0842</p> <span ui-badge variant="outline" class="text-xs">4 Responders</span> </div> <p class="text-muted-foreground text-xs">Bridge active · PagerDuty Sync</p> </div> </div> </div> </div> <!-- 2. 4 Incident KPI Telemetry Cards --> <div class="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4"> <!-- Card 1: Time to Detect --> <div ui-card class="border-border shadow-xs"> <div ui-card-content class="p-4"> <div class="flex items-center justify-between"> <p class="text-muted-foreground text-xs font-medium">Time to Detect (TTD)</p> <div class="border-warning/20 bg-warning/10 text-warning flex size-8 items-center justify-center rounded-lg border" > <lucide-icon [img]="Clock" class="size-4" aria-hidden="true" /> </div> </div> <div class="mt-2"> <div class="text-foreground font-mono text-2xl font-bold tracking-tight">4m 12s</div> <p class="text-muted-foreground mt-1 flex items-center gap-1 text-xs"> <lucide-icon [img]="CheckCircle2" class="text-success size-3 shrink-0" aria-hidden="true" /> <span>Automated GuardDuty alert fired</span> </p> </div> </div> </div> <!-- Card 2: Time to Mitigate --> <div ui-card class="border-border shadow-xs"> <div ui-card-content class="p-4"> <div class="flex items-center justify-between"> <p class="text-muted-foreground text-xs font-medium">Time to Mitigate (TTM)</p> <div class="border-destructive/20 bg-destructive/10 text-destructive flex size-8 items-center justify-center rounded-lg border" > <lucide-icon [img]="Zap" class="size-4" aria-hidden="true" /> </div> </div> <div class="mt-2"> <div class="text-foreground font-mono text-2xl font-bold tracking-tight">18m 45s</div> <p class="text-muted-foreground mt-1 flex items-center gap-1 text-xs"> <lucide-icon [img]="CheckCircle2" class="text-success size-3 shrink-0" aria-hidden="true" /> <span>Full perimeter isolation & rotation</span> </p> </div> </div> </div> <!-- Card 3: Affected Resources --> <div ui-card class="border-border shadow-xs"> <div ui-card-content class="p-4"> <div class="flex items-center justify-between"> <p class="text-muted-foreground text-xs font-medium">Affected Resources</p> <div class="border-info/20 bg-info/10 text-info flex size-8 items-center justify-center rounded-lg border" > <lucide-icon [img]="Server" class="size-4" aria-hidden="true" /> </div> </div> <div class="mt-2"> <div class="text-foreground font-mono text-2xl font-bold tracking-tight">3 Gateways</div> <p class="text-muted-foreground mt-1 flex items-center gap-1 font-mono text-xs"> <span>apigw-iad-prod-[01..03]</span> </p> </div> </div> </div> <!-- Card 4: Impacted User Accounts --> <div ui-card class="border-border shadow-xs"> <div ui-card-content class="p-4"> <div class="flex items-center justify-between"> <p class="text-muted-foreground text-xs font-medium">Impacted User Accounts</p> <div class="border-success/20 bg-success/10 text-success flex size-8 items-center justify-center rounded-lg border" > <lucide-icon [img]="Users" class="size-4" aria-hidden="true" /> </div> </div> <div class="mt-2"> <div class="text-success font-mono text-2xl font-bold tracking-tight">0 Compromised</div> <p class="text-muted-foreground mt-1 flex items-center gap-1 text-xs"> <lucide-icon [img]="ShieldCheck" class="text-success size-3 shrink-0" aria-hidden="true" /> <span>0 compromise confirmed · Token revoked</span> </p> </div> </div> </div> </div> <!-- 3. Incident Timeline (Vertical Connected Stream) --> <div ui-card class="border-border shadow-xs"> <div ui-card-header> <div class="flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between"> <div> <div ui-card-title class="text-lg font-bold">Incident Response Timeline</div> <div ui-card-description class="text-xs"> Chronological audit trail of SOC telemetry, containment actions, and mitigation milestones. </div> </div> <div class="flex items-center gap-2"> <span ui-badge variant="outline" class="font-mono text-xs"> 5 Timeline Events · UTC Synchronized </span> </div> </div> </div> <div ui-card-content class="pt-2"> <div class="before:bg-border relative space-y-8 pl-6 before:absolute before:top-3 before:bottom-3 before:left-3 before:w-px sm:pl-8 sm:before:left-4" > <!-- Timeline Entry 1: Detection --> <div class="relative space-y-3"> <div class="bg-card ring-background border-destructive/40 absolute -left-6 flex size-7 items-center justify-center rounded-full border shadow-xs ring-4 sm:-left-8 sm:size-8" > <lucide-icon [img]="ShieldAlert" class="text-destructive size-3.5 sm:size-4" aria-hidden="true" /> </div> <div class="flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between"> <div class="flex flex-wrap items-center gap-2"> <span class="text-foreground font-mono text-xs font-bold">2026-08-21T14:12:08Z</span> <span ui-badge variant="destructive" class="font-mono text-xs uppercase"> 1. Detection </span> <span ui-badge variant="outline" class="font-mono text-xs"> T+00:00 </span> <h3 class="text-foreground text-sm font-semibold">Automated Detection & Anomaly Ingestion</h3> </div> <div class="bg-muted/60 flex items-center gap-2 rounded-md border px-2.5 py-1 text-xs"> <ui-avatar class="size-5"> <ui-avatar-image src="https://i.pravatar.cc/60?img=60" alt="Marcus Vance" /> <ui-avatar-fallback class="text-xs">MV</ui-avatar-fallback> </ui-avatar> <span class="text-foreground font-medium">Marcus Vance</span> <span class="text-muted-foreground text-xs">(SecOps Lead)</span> </div> </div> <div class="space-y-1 text-xs"> <p class="text-foreground font-medium">Action Taken:</p> <p class="text-muted-foreground leading-relaxed"> AWS GuardDuty anomaly engine flagged an unauthorized STS AssumeRole policy elevation request targeting <code class="text-foreground bg-muted rounded px-1.5 py-0.5 font-mono text-xs" >role/SuperAdminPolicy</code > from an unapproved Tor exit node. Ingestion webhook routed alert to PagerDuty SecOps on-call. </p> </div> <div class="overflow-hidden rounded-md border bg-zinc-950 font-mono text-xs text-zinc-100 shadow-inner"> <div class="flex items-center justify-between border-b border-zinc-800 bg-zinc-900/90 px-3 py-1.5"> <div class="flex items-center gap-2"> <lucide-icon [img]="Terminal" class="text-muted-foreground size-3.5" aria-hidden="true" /> <span class="text-muted-foreground text-xs">guardduty_alert_stream.log</span> </div> <button ui-button variant="ghost" size="xs" class="h-6 gap-1 px-2 text-xs text-zinc-300 hover:bg-zinc-800 hover:text-zinc-100" (click)="copySnippet('detection')" > @if (copiedSnippetId() === 'detection') { <lucide-icon [img]="Check" class="text-success size-3" aria-hidden="true" /> } @else { <lucide-icon [img]="Copy" class="size-3" aria-hidden="true" /> } <span>{{ copiedSnippetId() === 'detection' ? 'Copied' : 'Copy Snippet' }}</span> </button> </div> <pre class="text-destructive/90 overflow-x-auto p-3 text-xs leading-relaxed select-text" ><code>{{ logSnippets.detection }}</code></pre> </div> <div class="bg-muted/40 rounded-lg border p-3 text-xs"> <span class="text-foreground font-semibold">Mitigation Notes: </span> <span class="text-muted-foreground"> Perimeter rate-limiting threshold exceeded (52 req/s). SIEM correlated 4 duplicate elevation signatures across edge ingress gateways. </span> </div> </div> <!-- Timeline Entry 2: Triage --> <div class="relative space-y-3"> <div class="bg-card ring-background border-warning/40 absolute -left-6 flex size-7 items-center justify-center rounded-full border shadow-xs ring-4 sm:-left-8 sm:size-8" > <lucide-icon [img]="Radio" class="text-warning size-3.5 sm:size-4" aria-hidden="true" /> </div> <div class="flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between"> <div class="flex flex-wrap items-center gap-2"> <span class="text-foreground font-mono text-xs font-bold">2026-08-21T14:15:30Z</span> <span ui-badge variant="warning" class="font-mono text-xs uppercase"> 2. Triage </span> <span ui-badge variant="outline" class="font-mono text-xs"> T+03:22 </span> <h3 class="text-foreground text-sm font-semibold">SOC Triage & Incident War Room Assembly</h3> </div> <div class="bg-muted/60 flex items-center gap-2 rounded-md border px-2.5 py-1 text-xs"> <ui-avatar class="size-5"> <ui-avatar-image src="https://i.pravatar.cc/60?img=47" alt="Elena Rostova" /> <ui-avatar-fallback class="text-xs">ER</ui-avatar-fallback> </ui-avatar> <span class="text-foreground font-medium">Elena Rostova</span> <span class="text-muted-foreground text-xs">(Incident Commander)</span> </div> </div> <div class="space-y-1 text-xs"> <p class="text-foreground font-medium">Action Taken:</p> <p class="text-muted-foreground leading-relaxed"> PagerDuty SEV-1 broadcast dispatched. Assembled SecOps, IAM, and Core Infrastructure leads in primary war room. Traced origin token <code class="text-foreground bg-muted rounded px-1.5 py-0.5 font-mono text-xs">tok_88f9x</code> to an ephemeral CI/CD GitHub Actions runner. </p> </div> <div class="overflow-hidden rounded-md border bg-zinc-950 font-mono text-xs text-zinc-100 shadow-inner"> <div class="flex items-center justify-between border-b border-zinc-800 bg-zinc-900/90 px-3 py-1.5"> <div class="flex items-center gap-2"> <lucide-icon [img]="Terminal" class="text-muted-foreground size-3.5" aria-hidden="true" /> <span class="text-muted-foreground text-xs">war_room_triage_audit.log</span> </div> <button ui-button variant="ghost" size="xs" class="h-6 gap-1 px-2 text-xs text-zinc-300 hover:bg-zinc-800 hover:text-zinc-100" (click)="copySnippet('triage')" > @if (copiedSnippetId() === 'triage') { <lucide-icon [img]="Check" class="text-success size-3" aria-hidden="true" /> } @else { <lucide-icon [img]="Copy" class="size-3" aria-hidden="true" /> } <span>{{ copiedSnippetId() === 'triage' ? 'Copied' : 'Copy Snippet' }}</span> </button> </div> <pre class="text-warning/90 overflow-x-auto p-3 text-xs leading-relaxed select-text" ><code>{{ logSnippets.triage }}</code></pre> </div> <div class="bg-muted/40 rounded-lg border p-3 text-xs"> <span class="text-foreground font-semibold">Mitigation Notes: </span> <span class="text-muted-foreground"> Confirmed unauthorized token attempt was using leaked CI/CD ephemeral workflow credential tok_88f9x. Scope bounded strictly to read-only API gateway routing. </span> </div> </div> <!-- Timeline Entry 3: Containment --> <div class="relative space-y-3"> <div class="bg-card ring-background border-warning/40 absolute -left-6 flex size-7 items-center justify-center rounded-full border shadow-xs ring-4 sm:-left-8 sm:size-8" > <lucide-icon [img]="Lock" class="text-warning size-3.5 sm:size-4" aria-hidden="true" /> </div> <div class="flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between"> <div class="flex flex-wrap items-center gap-2"> <span class="text-foreground font-mono text-xs font-bold">2026-08-21T14:22:15Z</span> <span ui-badge variant="warning" class="font-mono text-xs uppercase"> 3. Containment </span> <span ui-badge variant="outline" class="font-mono text-xs"> T+10:07 </span> <h3 class="text-foreground text-sm font-semibold">Perimeter Quarantine & Traffic Blackholing</h3> </div> <div class="bg-muted/60 flex items-center gap-2 rounded-md border px-2.5 py-1 text-xs"> <ui-avatar class="size-5"> <ui-avatar-image src="https://i.pravatar.cc/60?img=33" alt="David Okoye" /> <ui-avatar-fallback class="text-xs">DO</ui-avatar-fallback> </ui-avatar> <span class="text-foreground font-medium">David Okoye</span> <span class="text-muted-foreground text-xs">(Network Security)</span> </div> </div> <div class="space-y-1 text-xs"> <p class="text-foreground font-medium">Action Taken:</p> <p class="text-muted-foreground leading-relaxed"> Cloudflare WAF dynamic block rule enforced for egress IP ASN block (AS13335). Automated session kill command dispatched across all 3 production ingress proxy gateway clusters. </p> </div> <div class="overflow-hidden rounded-md border bg-zinc-950 font-mono text-xs text-zinc-100 shadow-inner"> <div class="flex items-center justify-between border-b border-zinc-800 bg-zinc-900/90 px-3 py-1.5"> <div class="flex items-center gap-2"> <lucide-icon [img]="Terminal" class="text-muted-foreground size-3.5" aria-hidden="true" /> <span class="text-muted-foreground text-xs">perimeter_waf_quarantine.log</span> </div> <button ui-button variant="ghost" size="xs" class="h-6 gap-1 px-2 text-xs text-zinc-300 hover:bg-zinc-800 hover:text-zinc-100" (click)="copySnippet('containment')" > @if (copiedSnippetId() === 'containment') { <lucide-icon [img]="Check" class="text-success size-3" aria-hidden="true" /> } @else { <lucide-icon [img]="Copy" class="size-3" aria-hidden="true" /> } <span>{{ copiedSnippetId() === 'containment' ? 'Copied' : 'Copy Snippet' }}</span> </button> </div> <pre class="text-warning/90 overflow-x-auto p-3 text-xs leading-relaxed select-text" ><code>{{ logSnippets.containment }}</code></pre> </div> <div class="bg-muted/40 rounded-lg border p-3 text-xs"> <span class="text-foreground font-semibold">Mitigation Notes: </span> <span class="text-muted-foreground"> Ingress gateways returned HTTP 403 Forbidden. External traffic from adversarial IP ranges suppressed with 0 packet leak into VPC internal mesh. </span> </div> </div> <!-- Timeline Entry 4: Token Revocation --> <div class="relative space-y-3"> <div class="bg-card ring-background border-info/40 absolute -left-6 flex size-7 items-center justify-center rounded-full border shadow-xs ring-4 sm:-left-8 sm:size-8" > <lucide-icon [img]="KeyRound" class="text-info size-3.5 sm:size-4" aria-hidden="true" /> </div> <div class="flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between"> <div class="flex flex-wrap items-center gap-2"> <span class="text-foreground font-mono text-xs font-bold">2026-08-21T14:30:53Z</span> <span ui-badge variant="info" class="font-mono text-xs uppercase"> 4. Token Revocation </span> <span ui-badge variant="outline" class="font-mono text-xs"> T+18:45 </span> <h3 class="text-foreground text-sm font-semibold"> Cryptographic Credential Invalidation & Key Rotation </h3> </div> <div class="bg-muted/60 flex items-center gap-2 rounded-md border px-2.5 py-1 text-xs"> <ui-avatar class="size-5"> <ui-avatar-image src="https://i.pravatar.cc/60?img=32" alt="Jessica Chen" /> <ui-avatar-fallback class="text-xs">JC</ui-avatar-fallback> </ui-avatar> <span class="text-foreground font-medium">Jessica Chen</span> <span class="text-muted-foreground text-xs">(IAM Engineering)</span> </div> </div> <div class="space-y-1 text-xs"> <p class="text-foreground font-medium">Action Taken:</p> <p class="text-muted-foreground leading-relaxed"> Revoked compromised GitHub Actions OIDC token series in AWS IAM & HashiCorp Vault. Rotated parent cluster KMS gateway signing keys and flushed authentication verification caches across Redis mesh. </p> </div> <div class="overflow-hidden rounded-md border bg-zinc-950 font-mono text-xs text-zinc-100 shadow-inner"> <div class="flex items-center justify-between border-b border-zinc-800 bg-zinc-900/90 px-3 py-1.5"> <div class="flex items-center gap-2"> <lucide-icon [img]="Terminal" class="text-muted-foreground size-3.5" aria-hidden="true" /> <span class="text-muted-foreground text-xs">vault_revocation_kms_rotation.log</span> </div> <button ui-button variant="ghost" size="xs" class="h-6 gap-1 px-2 text-xs text-zinc-300 hover:bg-zinc-800 hover:text-zinc-100" (click)="copySnippet('revocation')" > @if (copiedSnippetId() === 'revocation') { <lucide-icon [img]="Check" class="text-success size-3" aria-hidden="true" /> } @else { <lucide-icon [img]="Copy" class="size-3" aria-hidden="true" /> } <span>{{ copiedSnippetId() === 'revocation' ? 'Copied' : 'Copy Snippet' }}</span> </button> </div> <pre class="text-info/90 overflow-x-auto p-3 text-xs leading-relaxed select-text" ><code>{{ logSnippets.revocation }}</code></pre> </div> <div class="bg-muted/40 rounded-lg border p-3 text-xs"> <span class="text-foreground font-semibold">Mitigation Notes: </span> <span class="text-muted-foreground"> All downstream JWT verification caches invalidated via Redis Pub/Sub broadcast in 84ms. Zero active token survivability confirmed. </span> </div> </div> <!-- Timeline Entry 5: Post-Mortem Action Items --> <div class="relative space-y-3"> <div class="bg-card ring-background border-success/40 absolute -left-6 flex size-7 items-center justify-center rounded-full border shadow-xs ring-4 sm:-left-8 sm:size-8" > <lucide-icon [img]="ShieldCheck" class="text-success size-3.5 sm:size-4" aria-hidden="true" /> </div> <div class="flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between"> <div class="flex flex-wrap items-center gap-2"> <span class="text-foreground font-mono text-xs font-bold">2026-08-21T14:48:00Z</span> <span ui-badge variant="success" class="font-mono text-xs uppercase"> 5. Post-Mortem Action Items </span> <span ui-badge variant="outline" class="font-mono text-xs"> T+35:52 </span> <h3 class="text-foreground text-sm font-semibold"> Threat Vector Neutralized & Post-Mortem Transition </h3> </div> <div class="bg-muted/60 flex items-center gap-2 rounded-md border px-2.5 py-1 text-xs"> <ui-avatar class="size-5"> <ui-avatar-image src="https://i.pravatar.cc/60?img=60" alt="Marcus Vance" /> <ui-avatar-fallback class="text-xs">MV</ui-avatar-fallback> </ui-avatar> <span class="text-foreground font-medium">Marcus Vance</span> <span class="text-muted-foreground text-xs">(SecOps Lead)</span> </div> </div> <div class="space-y-1 text-xs"> <p class="text-foreground font-medium">Action Taken:</p> <p class="text-muted-foreground leading-relaxed"> Completed 15-minute clean traffic audit sweep with 0 anomalous requests. Incident commander officially downgraded active SEV-1 to Mitigated status and initiated formal post-mortem action items. </p> </div> <div class="overflow-hidden rounded-md border bg-zinc-950 font-mono text-xs text-zinc-100 shadow-inner"> <div class="flex items-center justify-between border-b border-zinc-800 bg-zinc-900/90 px-3 py-1.5"> <div class="flex items-center gap-2"> <lucide-icon [img]="Terminal" class="text-muted-foreground size-3.5" aria-hidden="true" /> <span class="text-muted-foreground text-xs">post_incident_audit_sweep.log</span> </div> <button ui-button variant="ghost" size="xs" class="h-6 gap-1 px-2 text-xs text-zinc-300 hover:bg-zinc-800 hover:text-zinc-100" (click)="copySnippet('postmortem')" > @if (copiedSnippetId() === 'postmortem') { <lucide-icon [img]="Check" class="text-success size-3" aria-hidden="true" /> } @else { <lucide-icon [img]="Copy" class="size-3" aria-hidden="true" /> } <span>{{ copiedSnippetId() === 'postmortem' ? 'Copied' : 'Copy Snippet' }}</span> </button> </div> <pre class="text-success/90 overflow-x-auto p-3 text-xs leading-relaxed select-text" ><code>{{ logSnippets.postmortem }}</code></pre> </div> <div class="bg-muted/40 rounded-lg border p-3 text-xs"> <span class="text-foreground font-semibold">Mitigation Notes: </span> <span class="text-muted-foreground"> Post-incident evidence bundle archived to secure S3 vault bucket <code class="text-foreground bg-muted rounded px-1 font-mono text-xs" >s3://sec-incidents-2026/0842-audit.tar.gz.enc</code >. Remediation tasks assigned. </span> </div> </div> </div> </div> </div> <!-- 4. Root Cause & Corrective Action Items Card --> <div ui-card class="border-border shadow-xs"> <div ui-card-header> <div class="flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between"> <div class="space-y-1"> <div class="flex items-center gap-2"> <lucide-icon [img]="FileCheck" class="text-primary size-5" aria-hidden="true" /> <div ui-card-title class="text-lg font-bold">Root Cause Analysis & Corrective Action Items</div> </div> <div ui-card-description class="text-xs"> 3 actionable remediation tasks tracked across Jira and GitHub to prevent recurring authorization bypass vectors. </div> </div> <span ui-badge variant="outline" class="w-fit font-mono text-xs"> 3 Post-Mortem Tasks </span> </div> </div> <div ui-card-content class="space-y-4"> <!-- Root Cause Summary Box --> <div class="bg-muted/30 border-border space-y-1.5 rounded-lg border p-3.5 text-xs"> <div class="text-foreground flex items-center gap-2 font-semibold"> <lucide-icon [img]="Shield" class="text-warning size-4" aria-hidden="true" /> <span>Root Cause Summary</span> </div> <p class="text-muted-foreground leading-relaxed"> A third-party fork pull request executed via a workflow using <code class="text-foreground bg-muted rounded px-1 py-0.5 font-mono">pull_request_target</code> allowed unauthorized extraction of the short-lived CI OIDC token. AWS STS role trust policy lacked strict <code class="text-foreground bg-muted rounded px-1 py-0.5 font-mono">repository_owner</code> and <code class="text-foreground bg-muted rounded px-1 py-0.5 font-mono">ref</code> claim constraints. </p> </div> <!-- Task List Items --> <div class="border-border divide-border divide-y rounded-lg border"> <!-- Task 1 --> <div class="hover:bg-muted/20 flex flex-col gap-3 p-3.5 transition-colors sm:flex-row sm:items-center sm:justify-between" > <div class="flex items-start gap-3"> <div class="pt-0.5"> <ui-checkbox id="task-sec-4412" [checked]="actionItem1()" (checkedChange)="actionItem1.set(!!$event)" /> </div> <div class="space-y-1"> <div class="flex flex-wrap items-center gap-2"> <label for="task-sec-4412" [class]="taskLabelClass(actionItem1())"> SEC-4412 </label> <span ui-badge variant="destructive" class="font-mono text-xs">P0 Blocker</span> <span ui-badge variant="warning" class="font-mono text-xs">In Review</span> </div> <p [class]="taskDescClass(actionItem1())"> Enforce strict OIDC branch-to-role binding with repository claim validation on CI runner STS policies </p> <p class="text-muted-foreground text-xs"> Require <code class="font-mono text-xs">repository_owner=uipkge</code> and <code class="font-mono text-xs">ref=refs/heads/main</code> on all assumed cloud roles. </p> </div> </div> <div class="flex shrink-0 flex-wrap items-center gap-3 pl-7 sm:justify-end sm:pl-0"> <div class="bg-muted/60 flex items-center gap-1.5 rounded-md border px-2 py-1 text-xs"> <ui-avatar class="size-4"> <ui-avatar-image src="https://i.pravatar.cc/50?img=32" alt="Jessica Chen" /> <ui-avatar-fallback class="text-xs">JC</ui-avatar-fallback> </ui-avatar> <span class="text-foreground font-medium">Jessica Chen</span> </div> <span ui-badge variant="outline" class="gap-1 font-mono text-xs"> <lucide-icon [img]="GitPullRequest" class="size-3" aria-hidden="true" /> PR #882 </span> </div> </div> <!-- Task 2 --> <div class="hover:bg-muted/20 flex flex-col gap-3 p-3.5 transition-colors sm:flex-row sm:items-center sm:justify-between" > <div class="flex items-start gap-3"> <div class="pt-0.5"> <ui-checkbox id="task-sec-4413" [checked]="actionItem2()" (checkedChange)="actionItem2.set(!!$event)" /> </div> <div class="space-y-1"> <div class="flex flex-wrap items-center gap-2"> <label for="task-sec-4413" [class]="taskLabelClass(actionItem2())"> SEC-4413 </label> <span ui-badge variant="warning" class="font-mono text-xs">P1 High</span> <span ui-badge variant="success" class="font-mono text-xs">Completed</span> </div> <p [class]="taskDescClass(actionItem2())"> Reduce default ephemeral CI token TTL from 3600s to 900s across all GitHub Actions deployment workflows </p> <p class="text-muted-foreground text-xs"> Update HashiCorp Vault AWS secrets engine configuration and OIDC provider default duration. </p> </div> </div> <div class="flex shrink-0 flex-wrap items-center gap-3 pl-7 sm:justify-end sm:pl-0"> <div class="bg-muted/60 flex items-center gap-1.5 rounded-md border px-2 py-1 text-xs"> <ui-avatar class="size-4"> <ui-avatar-image src="https://i.pravatar.cc/50?img=33" alt="David Okoye" /> <ui-avatar-fallback class="text-xs">DO</ui-avatar-fallback> </ui-avatar> <span class="text-foreground font-medium">David Okoye</span> </div> <span ui-badge variant="outline" class="gap-1 font-mono text-xs"> Deployed v4.18.2 </span> </div> </div> <!-- Task 3 --> <div class="hover:bg-muted/20 flex flex-col gap-3 p-3.5 transition-colors sm:flex-row sm:items-center sm:justify-between" > <div class="flex items-start gap-3"> <div class="pt-0.5"> <ui-checkbox id="task-sec-4414" [checked]="actionItem3()" (checkedChange)="actionItem3.set(!!$event)" /> </div> <div class="space-y-1"> <div class="flex flex-wrap items-center gap-2"> <label for="task-sec-4414" [class]="taskLabelClass(actionItem3())"> SEC-4414 </label> <span ui-badge variant="warning" class="font-mono text-xs">P1 High</span> <span ui-badge variant="info" class="font-mono text-xs">In Progress</span> </div> <p [class]="taskDescClass(actionItem3())"> Implement automated SIEM quarantine webhook to auto-revoke Vault tokens upon GuardDuty high-severity finding </p> <p class="text-muted-foreground text-xs"> Deploy AWS EventBridge rule to pipe GuardDuty high-severity IAM alerts directly to Lambda quarantine webhook. </p> </div> </div> <div class="flex shrink-0 flex-wrap items-center gap-3 pl-7 sm:justify-end sm:pl-0"> <div class="bg-muted/60 flex items-center gap-1.5 rounded-md border px-2 py-1 text-xs"> <ui-avatar class="size-4"> <ui-avatar-image src="https://i.pravatar.cc/50?img=60" alt="Marcus Vance" /> <ui-avatar-fallback class="text-xs">MV</ui-avatar-fallback> </ui-avatar> <span class="text-foreground font-medium">Marcus Vance</span> </div> <span ui-badge variant="outline" class="gap-1 font-mono text-xs"> Sprint 34 · Aug 28 </span> </div> </div> </div> </div> </div> </div> `, }) export class UiSecurityIncidentTimelineComponent { protected readonly Check = Check protected readonly CheckCircle2 = CheckCircle2 protected readonly Clock = Clock protected readonly Copy = Copy protected readonly FileCheck = FileCheck protected readonly FileDown = FileDown protected readonly GitPullRequest = GitPullRequest protected readonly KeyRound = KeyRound protected readonly Lock = Lock protected readonly Plus = Plus protected readonly Radio = Radio protected readonly Server = Server protected readonly Shield = Shield protected readonly ShieldAlert = ShieldAlert protected readonly ShieldCheck = ShieldCheck protected readonly Terminal = Terminal protected readonly Users = Users protected readonly Zap = Zap protected readonly logSnippets = logSnippets @Input() incidentId = '#SEC-INC-2026-0842' @Input() incidentTitle = 'Unauthorized API Token Elevation Attempt' @Input() severity = 'SEV-1 Critical' @Input() status = 'Mitigated / In Post-Mortem' @Input() commanderName = 'Marcus Vance' @Input() commanderRole = 'Principal SecOps · Incident Commander' @Input('class') className?: string readonly isResolved = signal(false) readonly exportNotification = signal(false) readonly copiedSnippetId = signal<string | null>(null) readonly updateAddedNotification = signal(false) readonly actionItem1 = signal(true) readonly actionItem2 = signal(true) readonly actionItem3 = signal(false) get rootClass(): string { return cn('w-full space-y-6', this.className) } taskLabelClass(done: boolean): string { return cn( 'cursor-pointer font-mono text-xs font-bold', done ? 'text-muted-foreground line-through' : 'text-foreground', ) } taskDescClass(done: boolean): string { return cn('text-xs font-medium', done ? 'text-muted-foreground line-through' : 'text-foreground') } copySnippet(id: string): void { const text = logSnippets[id] if (!text) return try { void navigator.clipboard.writeText(text) } catch { // Clipboard unavailable: still flip the label. } this.copiedSnippetId.set(id) setTimeout(() => { if (this.copiedSnippetId() === id) this.copiedSnippetId.set(null) }, 2000) } handleExportPdf(): void { this.exportNotification.set(true) setTimeout(() => this.exportNotification.set(false), 2500) } handleAddUpdate(): void { this.updateAddedNotification.set(true) setTimeout(() => this.updateAddedNotification.set(false), 2500) } handleResolve(): void { this.isResolved.update((v) => !v) } }src/app/components/blocks/security-incident-timeline/index.ts0.1 kB
export { UiSecurityIncidentTimelineComponent } from './security-incident-timeline.component'
Raw manifest:https://uipkge.dev/r/angular/security-incident-timeline.json