Audit trail includes all user actions: login, transfer, withdrawal, adjustment, cancellation
Why it matters
A transaction log that records transfers but silently omits login events, fee adjustments, and account cancellations is not a complete audit trail — it is a partial record that creates blind spots regulators will find. NIST 800-53 AU-2 requires organizations to determine which event types are auditable and to coordinate the audit function with other entities requiring audit-related information; login/logout events are explicitly called out. PCI-DSS 4.0 Req-10.2.1 enumerates specific event types that must be logged: all individual user access to cardholder data, all actions taken by any individual with root or administrative privileges, and all invalid logical access attempts. FINRA Rule 4511 requires complete books and records. CWE-778 (Insufficient Logging) is the vulnerability. An attacker who escalates privileges via a path that does not trigger a log event leaves no forensic evidence of the intrusion.
Severity rationale
Medium because partial action coverage creates audit gaps that satisfy automated checks while concealing specific attack paths — particularly privilege escalation routes — from forensic investigation.
Remediation
Instrument every significant user action through a centralized logger in src/services/audit-logger.ts to ensure consistent coverage:
const AUDITABLE_OPERATIONS = [
'login', 'logout', 'transfer', 'withdrawal', 'deposit',
'adjustment', 'cancellation', 'reversal', 'fee_change'
] as const;
export async function logAction(
userId: string,
operation: typeof AUDITABLE_OPERATIONS[number],
details: Record<string, unknown>
) {
await db('transaction_logs').insert({
user_id: userId,
operation_type: operation,
details: JSON.stringify(details),
timestamp: new Date().toISOString()
});
}
Call logAction in each route — for login events, call it after successful credential verification, not only on successful session creation, so failed login attempts are also captured.
Detection
-
ID:
complete-action-logging -
Severity:
medium -
What to look for: Enumerate all user-facing operation endpoints (at minimum: login, logout, transfer, withdrawal, deposit, adjustment, cancellation, reversal, fee modification). Count every endpoint and classify each as "logged" or "not logged." Quote the actual operation_type values found in logging calls. At least 6 distinct action types should be recognized. An endpoint that performs a financial operation without writing to the audit log does not count as pass.
-
Pass criteria: At least 90% of significant user action endpoints are logged with operation type and outcome. Count all action types — at least 6 distinct types must be present (login, transfer, withdrawal, deposit, adjustment, cancellation). Report the ratio even on pass (e.g., "8 of 9 action types logged, including login/logout").
-
Fail criteria: Fewer than 90% of operation types have logging, or fewer than 6 distinct action types are logged, or login/logout events are not recorded.
-
Skip (N/A) when: Never — comprehensive action logging is required for compliance.
-
Detail on fail: Name the action types not logged. Example:
"5 of 8 action types logged — fee adjustments, manual corrections, and logout are missing."or"Login/logout events are not recorded — 0 auth-event entries found in audit trail.". -
Cross-reference: Check
finserv-audit-trail.transaction-logging.transaction-immutable-loggingfor transaction-specific logging, andfinserv-audit-trail.retention-compliance.config-change-loggingfor admin config changes. -
Remediation: Ensure all user-initiated financial actions log events (in
src/services/audit-logger.tsor equivalent):async function adjustFee(userId, accountId, newFee, reason) { const oldFee = await db.accounts.findOne({ accountId }).select('monthly_fee'); await db.accounts.update({ accountId }, { monthly_fee: newFee }); // Log the adjustment await db.transactionLogs.create({ userId, operationType: 'fee_adjustment', details: { accountId, oldFee, newFee, reason, adjustedBy: userId }, timestamp: new Date().toISOString() }); } // Similarly for login events app.post('/api/login', async (req, res) => { const user = await authenticateUser(req.body.email, req.body.password); if (user) { await db.transactionLogs.create({ userId: user.id, operationType: 'login', timestamp: new Date().toISOString() }); } });
External references
- cwe · CWE-778 — Insufficient Logging
- nist:rev5 · AU-2 — Event Logging — identify events to be logged
- pci-dss:4.0 · Req-10.2.1 — Implement audit logs to capture all individual user access and actions on cardholder data
- external · FINRA-Rule-4511 — FINRA Rule 4511 — General Requirements for Books and Records
Taxons
History
- 2026-04-18·v1.0.0·Initial import from finserv-audit-trail·automated