models/AuditLogModel.php::deleteOldLogs() (~lines 312-323), called daily by cron/cleanup_audit_log.php — a single unbounded DELETE FROM audit_log WHERE created_at < ?. created_at is indexed so row selection itself is efficient, but on a large qualifying row set (e.g. the first run after enabling/changing AUDIT_LOG_RETENTION_DAYS, or after the cron job silently failed to run for a while) an unbounded single-statement DELETE holds row locks for the full duration of the transaction — risking lock contention with the frequent concurrent INSERTs the audit log receives from live traffic (nearly every user action logs a row).
Fix: Batch the delete (e.g. DELETE ... ORDER BY created_at LIMIT 1000 in a loop until no rows remain) to bound lock hold time per statement.
**Severity:** Low
`models/AuditLogModel.php::deleteOldLogs()` (~lines 312-323), called daily by `cron/cleanup_audit_log.php` — a single unbounded `DELETE FROM audit_log WHERE created_at < ?`. `created_at` is indexed so row selection itself is efficient, but on a large qualifying row set (e.g. the first run after enabling/changing `AUDIT_LOG_RETENTION_DAYS`, or after the cron job silently failed to run for a while) an unbounded single-statement `DELETE` holds row locks for the full duration of the transaction — risking lock contention with the frequent concurrent `INSERT`s the audit log receives from live traffic (nearly every user action logs a row).
**Fix:** Batch the delete (e.g. `DELETE ... ORDER BY created_at LIMIT 1000` in a loop until no rows remain) to bound lock hold time per statement.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Severity: Low
models/AuditLogModel.php::deleteOldLogs()(~lines 312-323), called daily bycron/cleanup_audit_log.php— a single unboundedDELETE FROM audit_log WHERE created_at < ?.created_atis indexed so row selection itself is efficient, but on a large qualifying row set (e.g. the first run after enabling/changingAUDIT_LOG_RETENTION_DAYS, or after the cron job silently failed to run for a while) an unbounded single-statementDELETEholds row locks for the full duration of the transaction — risking lock contention with the frequent concurrentINSERTs the audit log receives from live traffic (nearly every user action logs a row).Fix: Batch the delete (e.g.
DELETE ... ORDER BY created_at LIMIT 1000in a loop until no rows remain) to bound lock hold time per statement.