Security Logging skill for Codex

Logs that answer who, what, where, when. Codex designs security logging around the investigation you will actually run: a defined set of authentication, authorization, account and data-access events in a consistent structured schema, central tamper-evident storage with sane retention, and centrally enforced redaction so passwords, tokens and PANs never reach the log store. It then turns those events into detections with owners.

  • Security
  • $security-logging
  • 128 lines
  • 2 files
  • ~1,500 tokens
  • MIT
  • Updated

Install

curl -fsSL codexskills.dev/install.sh \  | sh -s -- security-logging

Installs to ~/.agents/skills/security-logging/ for every project on this machine.

104-line POSIX script. No sudo, no telemetry. Read install.sh

Use it in Codex

Start a prompt with $security-logging, or pick it from /skills. You can also just describe the task: Codex reads the description below and loads the playbook when your request matches.

What Codex reads before loading it

Designs security and audit logging that an investigation can actually use - which events to log (authentication, authorization, account and privilege changes, data access, admin actions), a consistent structured schema, what must never be logged (passwords, tokens, full PANs, secrets), tamper resistance and retention, and detections/alerts built on the events. Use when adding an audit trail, deciding what to log for security, meeting SOC 2 or PCI logging requirements, redacting sensitive data from logs, or turning logs into alerts.

Use it when

  • You are adding an audit trail or security event log
  • An audit (SOC 2, PCI) requires specific logging and retention
  • Secrets or PII are leaking into existing logs
  • You want detections built on logged security events

Use something else when

  • You are building alert routing and on-call SLOs: use alerting-rules
  • You are investigating an incident from existing logs: use log-forensics

How to check the result

Each key event appears in the central store with all standard fields when triggered in staging, a secrets grep over a day of logs finds nothing, and a simulated attack pattern fires its detection.

The mistake it prevents

Logging whole request and response bodies for debugging, which quietly writes passwords, tokens and personal data into the log store.

~/.agents/skills/security-logging/SKILL.md

--- name: security-logging description: Designs security and audit logging that an investigation can actually use - which events to log (authentication, authorization, account and privilege… license: MIT ---

Done well means: when something goes wrong, the logs answer who did what, to what, from where, and when — and they contain no secrets that turn the log store into the next breach. Log for the investigation you will run under pressure, not for everything just in case.

Decide what to log

Security-relevant events, each with enough context to reconstruct an action:

CategoryEvents
AuthenticationLogin success and failure (with reason category), logout, MFA challenge/result, password reset, token issued/refreshed/revoked, session created/expired
AuthorizationAccess denied (403), privilege check failures, step-up auth
Account lifecycleCreate, disable, delete, role/permission change, group membership change, email/MFA change
Admin and configSettings changes, feature flags, key rotation, impersonation (“act as user”), data export
Sensitive data accessRead/write of regulated records (who read which patient/customer record)
Security eventsRate-limit trips, WAF blocks, input validation rejections, integrity check failures

For each, capture a standard set of fields so events join across services.

{
  "timestamp": "2026-10-28T09:14:22.512Z",
  "event": "auth.login.failure",
  "outcome": "failure",
  "reason": "bad_password",
  "actor": {"id": "u_8832", "type": "user", "session": "s_a91f"},
  "source": {"ip": "203.0.113.9", "user_agent": "...", "request_id": "r_2c7"},
  "target": {"type": "account", "id": "u_8832"},
  "service": "auth-api",
  "env": "prod"
}
  • Use UTC, ISO 8601 with milliseconds. Log request_id/trace ID so one request stitches across services. Include the outcome explicitly; “login” without success/failure is nearly useless.
  • Use stable, enumerated event names (noun.verb.outcome) so detections match on a field, not a regex over free text.
  • For “access denied”, log the subject, the resource, and the permission that failed — that is what a privilege-escalation hunt needs.

Never log these

  • Passwords, password hashes, security answers.
  • Session tokens, API keys, bearer/JWT values, OAuth codes, CSRF tokens, reset tokens.
  • Full PANs (PCI: mask to first 6 / last 4 max), CVV (never), full government IDs.
  • Secrets, private keys, full request bodies of auth or payment endpoints.
  • More personal data than the event needs (log an opaque user ID, not full profiles).

Enforce redaction centrally in the logging layer, not per call site:

REDACT = ("password", "pwd", "secret", "token", "authorization",
          "api_key", "apikey", "set-cookie", "ssn", "card", "cvv")

def scrub(obj):
    if isinstance(obj, dict):
        return {k: ("***" if any(r in k.lower() for r in REDACT) else scrub(v))
                for k, v in obj.items()}
    if isinstance(obj, (list, tuple)):
        return [scrub(v) for v in obj]
    return obj

Also scrub at the collector (a Vector/Fluent Bit transform) as defence in depth, and keep tokens out of URLs so they never reach access logs.

Where logs go and how they survive

  • Ship off the host to a central store (SIEM, OpenSearch, Loki, CloudWatch, a managed platform). A log only on the compromised box is evidence the attacker can erase.
  • Make them append-only/tamper-evident: write-once storage (S3 Object Lock), restricted IAM so the app can write but not delete, and ideally a hash chain or signed batches for high-value audit trails. Separate the account/project that holds logs from the one being logged.
  • Retention: set by policy and regulation. Common anchors — PCI DSS requires at least 12 months with 3 months readily available; SOC 2 and many audits expect 12 months. Confirm the number against the org’s policy; it governs storage cost and legal exposure.
  • Time sync (NTP) across hosts, or correlation across services falls apart.

Turn events into detections

Logging without alerting is just storage. Build detections on the structured events:

DetectionSignal
Password sprayingMany auth.login.failure across many accounts from few IPs in a short window
Brute forceMany failures on one account
Impossible travelLogins for one user from distant geos within minutes
Privilege escalationaccount.role.change granting admin, or impersonation by non-admin
Mass data accessOne actor reading far more records than their baseline
Log tamperingGap in sequence, logging agent stopped, integrity check failure

Alerts need an owner, a runbook link, and tuning so they do not drown the on-call. Route them to where responders actually look. Alerting mechanics and SLOs live in $alerting-rules and $incident-response; this skill decides which security events deserve an alert.

Gotchas

  • Logging full request/response bodies “for debugging” is the most common way secrets and PII end up in logs. Allowlist fields instead of logging whole objects.
  • Verbose logs of failed auth can themselves leak which usernames exist; log a reason category, not “user not found” vs “wrong password” differences that reach the client.
  • Over-logging buries signal and runs up cost; sample high-volume non-security logs, never sample security events.
  • Client-supplied fields (IP from X-Forwarded-For, user agent) are attacker-controlled; record them as claimed, and trust the edge/proxy-derived IP for decisions.
  • Deleting a user must not delete their audit trail; audit logs often outlive the account (reconcile with retention and privacy policy).

Verification

  • Trigger each key event (a failed login, a role change, a denied access) in staging and confirm it lands in the central store with all standard fields populated.
  • Grep a day of logs for secrets patterns and confirm nothing leaks: rg -n "password|eyJ|Bearer [A-Za-z0-9._-]{10,}|AKIA|[0-9]{13,16}" sample.log.
  • Fire a detection by simulating the pattern (for example 50 failed logins) and confirm the alert triggers and routes.
  • Confirm append-only: attempt a delete with the app’s own credentials and verify it is denied.

What the zip contains

SKILL.md plus the interface file below. Nothing runs on install.

agents/openai.yamlgenerated from this page

Gives the Codex app a display name, a one-line description and a starter prompt for this skill.

interface:
  display_name: "Security Logging"
  short_description: "Logs that answer who, what, where, when"
  default_prompt: "$security-logging Design an audit log for account and permission changes in our app"

About this skill

Written and maintained by the Codex Skills editors to the same editorial standard as every skill here: a selective description, a real workflow, known pitfalls and a way to verify the work. First published , last updated . MIT licensed. Something wrong or out of date? Tell us.

esc