Skip to content

v0.5.0 — Selectable chat-alert categories

Choose a tag to compare

@anhtuank7c anhtuank7c released this 26 May 11:38
· 33 commits to main since this release

Minor release. Adds the first user-configurable filter over chat alerts — enable_notification_type lets operators opt in to specific event categories (login_success, login_failed, session_open, session_close, brute_force, all) rather than receiving every PAM event. Requested by @huy-lv (#22) for the common deployment shape where the host's notable signal is "someone got in" rather than "someone tried." The filter gates chat dispatch only — journalctl -t pamsignal still records every event, so the forensic trail and threat-model assumptions are unchanged. Default is all, so existing deployments behave identically without touching their config. Beneath the new filter, the existing per-event suppression for sudo/su LOGIN_FAILED (only the brute-force aggregate fires for those services) is untouched. Also ships two transitive-dependency security bumps in the bundled example receivers (idna CVE-2026-45409 in the Python receiver, qs CVE-2026-8723 in the Node.js receiver) — neither affects the C daemon, but the examples need to install cleanly into their own ecosystems. Internal: 13 new CMocka cases (9 config + 4 notify gating), zero new build warnings, ASVS L1 pre-merge gate clean.

Features

  • enable_notification_type config key — select which event categories fire a chat alert (#22). Reported by @huy-lv. Comma-separated list of tokens: login_success, login_failed, session_open, session_close, brute_force, or all. Default — when the key is omitted or set to all — is every category, so existing deployments behave unchanged. Filters only the chat dispatch (Telegram / Slack / Teams / WhatsApp / Discord / custom webhook); the local journalctl -t pamsignal trail records every event regardless, preserving the forensic record assumed by docs/threat-model.md. Unknown tokens, empty values, and empty list elements are hard errors at config load (matches the strictness of the existing validators). Implemented as a 5-bit mask on ps_config_t.enable_notification_type (PS_NOTIFY_LOGIN_SUCCESS, PS_NOTIFY_LOGIN_FAILED, PS_NOTIFY_SESSION_OPEN, PS_NOTIFY_SESSION_CLOSE, PS_NOTIFY_BRUTE_FORCE); ps_notify_event gates on the per-event-type bit and ps_notify_brute_force / ps_notify_local_brute_force gate on the brute-force bit. The existing per-event suppression for sudo/su LOGIN_FAILED in src/journal_watch.c is unchanged and layered beneath this filter. Parser handles arbitrary whitespace around list elements and is case-insensitive on token names. Tests: 9 new CMocka cases in tests/test_config.c (default = all, single category, multi-category CSV, all sentinel, whitespace + case tolerance, full 5-category list, unknown token rejected, empty value rejected, empty list element rejected, omitted-key keeps default) and 4 new cases in tests/test_notify.c exercising the dispatch gate via the file-static cooldown clock (event_notify_bit mapping, gated-off doesn't dispatch, gated-on does dispatch, PS_EVENT_UNKNOWN never dispatches). Documented in docs/configuration.md (new "Notification-type filter" section with token table, scope note, examples) and pamsignal.conf.example.

Security

  • examples/nodejs-webhook/: bump qs 6.14.2 / 6.15.1 → 6.15.2 in pnpm-lock.yaml (Dependabot alert #2, CVE-2026-8723, CVSS v4 6.3 medium). qs >= 6.11.1, <= 6.15.1 throws TypeError synchronously when qs.stringify is called with both arrayFormat: 'comma' and encodeValuesOnly: true on an array containing null/undefined — the raw encoder runs before skipNulls/strictNullHandling get a chance to handle the bad element. Under Express the throw is caught by the framework error boundary and returns 500; outside a handler (background jobs, startup paths) it crashes the worker. PAMSignal itself is C and unaffected; the alert fires only on the Express example receiver's transitive qs (via express, body-parser, formidable, supertest). Pinned via pnpm overrides in pnpm-workspace.yaml so both 6.14.2 (express 4.x) and 6.15.1 (body-parser / formidable) collapse to the patched 6.15.2; package.json direct deps unchanged. All 64 jest tests still pass.
  • examples/python-webhook/: bump idna 3.14 → 3.15 in uv.lock (Dependabot alert #1, CVE-2026-45409, CVSS v4 6.9 medium). idna < 3.15 is vulnerable to a DoS when idna.encode() is called with crafted long inputs (e.g. "٠" * N): valid_contexto runs before the length-rejection check, re-opening the gap that CVE-2024-3651 was supposed to close. PAMSignal itself is C and unaffected; the alert fires only on the Flask example receiver's transitive dep via requests. Lockfile-only refresh via uv lock --upgrade-package idna; pyproject.toml unchanged.