Found by the security review of #470 (low severity, requires a privileged principal).
Denials are coalesced within a 60 second window, because a client could otherwise grow
the log without bound. Failures are not. An authenticated caller holding
manage_users, or any mutation permission, can repeat a request that deterministically
fails, such as creating a user that already exists, and every attempt appends a
failure row carrying the full cause.Error() text.
The effect is that an insider with admin rights can bury the events that matter and
inflate auth.db. It needs a privileged account, which is why it is low rather than
higher.
Suggested fix: run failures through the same admitDenial-style coalescing, keyed on
actor, action, target and error, and cap ev.Error" at a fixed length (500 bytes would do) in both recordFailureandRecordDeniedWithDetails`.
Also worth picking up whilst in that code: deniedAction writes the client's HTTP
method into action as rbac.<method>, and printAuditTable sanitises actor, target
and error but not action. Go's server rejects methods containing control characters,
so this is not an injection route, but sanitising action too would be consistent.
Found by the security review of #470 (low severity, requires a privileged principal).
Denials are coalesced within a 60 second window, because a client could otherwise grow
the log without bound. Failures are not. An authenticated caller holding
manage_users, or any mutation permission, can repeat a request that deterministicallyfails, such as creating a user that already exists, and every attempt appends a
failurerow carrying the fullcause.Error()text.The effect is that an insider with admin rights can bury the events that matter and
inflate
auth.db. It needs a privileged account, which is why it is low rather thanhigher.
Suggested fix: run failures through the same
admitDenial-style coalescing, keyed onactor, action, target and error, and cap
ev.Error" at a fixed length (500 bytes would do) in bothrecordFailureandRecordDeniedWithDetails`.Also worth picking up whilst in that code:
deniedActionwrites the client's HTTPmethod into
actionasrbac.<method>, andprintAuditTablesanitises actor, targetand error but not
action. Go's server rejects methods containing control characters,so this is not an injection route, but sanitising
actiontoo would be consistent.