BLOCKER: authenticated Notes sessions do not enforce credential expiry #787

Open
opened 2026-10-02 13:10:44 +00:00 by kayg · 2 comments
Owner

Protocol audit assigned under #663; source base c4a61e8cf0. Source review only; no hostile payload, live exploit or crash-threshold measurement. The owner rule blocks authorization holes and crash/DoS risks. No product code is changed by this audit.

Evidence: notes_imap.rs:225–258 checks current User disablement, plugin
enablement and whether the App Password ID appears in list_app_passwords.
calternal-auth/src/store.rs:1179–1185 excludes revoked rows but retains
expired rows. AppPassword::allows (:373) checks scopes only. The live check
does not compare expires_at. LOGIN and initial use recording do check
expiry (store.rs:1233, :1292), so new connections fail after expiry while
existing ones can remain authorized. IDLE uses the same live check every
60 seconds (notes_imap.rs:464). SMTP also uses it (notes_submission.rs:143).

Impact: an already signed-in Notes client retains read/write access after the
App Password expires. Repeated valid commands can keep the connection alive.
The SMTP stub still refuses mail, so this does not create a relay. The same
check persists in round-7a and committed mailproxy-486.

Repair: add a current-credential validity query that checks User identity,
disablement, revocation and expiry together. Use it for each command and IDLE
wake/lease check. Keep list_app_passwords suitable for Settings; expired
rows there are useful and must not be treated as active grants.

Regression coverage: an injected clock crossing expiry while a connection
is already open; IMAP commands and IDLE; SMTP validity; no data emitted and
no write committed after expiry. Test revocation separately from expiry.

Duplicate check: searched all issue states for XML depth, connection cap, SSE revocation and MCP session. Read related #457, #328, #329 and #668. No matching repair issue identified. Track the repair with source-level tests and a safe local validation of the repaired boundary. Do not close this issue from the audit job.

Protocol audit assigned under #663; source base c4a61e8cf090170f35b1bed3350d9de20c83ecd5. Source review only; no hostile payload, live exploit or crash-threshold measurement. The owner rule blocks authorization holes and crash/DoS risks. No product code is changed by this audit. Evidence: `notes_imap.rs:225–258` checks current User disablement, plugin enablement and whether the App Password ID appears in `list_app_passwords`. `calternal-auth/src/store.rs:1179–1185` excludes revoked rows but retains expired rows. `AppPassword::allows` (`:373`) checks scopes only. The live check does not compare `expires_at`. LOGIN and initial use recording do check expiry (`store.rs:1233`, `:1292`), so new connections fail after expiry while existing ones can remain authorized. IDLE uses the same live check every 60 seconds (`notes_imap.rs:464`). SMTP also uses it (`notes_submission.rs:143`). Impact: an already signed-in Notes client retains read/write access after the App Password expires. Repeated valid commands can keep the connection alive. The SMTP stub still refuses mail, so this does not create a relay. The same check persists in round-7a and committed mailproxy-486. Repair: add a current-credential validity query that checks User identity, disablement, revocation and expiry together. Use it for each command and IDLE wake/lease check. Keep `list_app_passwords` suitable for Settings; expired rows there are useful and must not be treated as active grants. Regression coverage: an injected clock crossing expiry while a connection is already open; IMAP commands and IDLE; SMTP validity; no data emitted and no write committed after expiry. Test revocation separately from expiry. Duplicate check: searched all issue states for XML depth, connection cap, SSE revocation and MCP session. Read related #457, #328, #329 and #668. No matching repair issue identified. Track the repair with source-level tests and a safe local validation of the repaired boundary. Do not close this issue from the audit job.
Author
Owner

Reuse evidence from round-7a (2f4482ded0): crates/calternal-server/src/mcp_events.rs:384–400 already checks p.expires_at before delivery after list_app_passwords. This confirms that Settings listing rows alone are not treated as active grants on that protocol. Extract or reuse the current-credential predicate when fixing Notes IMAP/SMTP, rather than changing the list endpoint to hide expired credentials. No product edit made by the audit.

Reuse evidence from round-7a (2f4482ded066d9c5d9c59130377907f7fd2916c9): crates/calternal-server/src/mcp_events.rs:384–400 already checks p.expires_at before delivery after list_app_passwords. This confirms that Settings listing rows alone are not treated as active grants on that protocol. Extract or reuse the current-credential predicate when fixing Notes IMAP/SMTP, rather than changing the list endpoint to hide expired credentials. No product edit made by the audit.
Author
Owner

Settings listing includes expired App Passwords. Added active_app_password with a User join, current expiry, revocation and scope read; Notes IMAP commands/IDLE and SMTP now use it. Captured scope changes close the connection so a write grant cannot survive a downgrade. Injected-clock store test covers exact expiry, foreign identity, disablement, revocation and Settings retention.
Validation is in progress. No completion or live exploit claim.

Settings listing includes expired App Passwords. Added active_app_password with a User join, current expiry, revocation and scope read; Notes IMAP commands/IDLE and SMTP now use it. Captured scope changes close the connection so a write grant cannot survive a downgrade. Injected-clock store test covers exact expiry, foreign identity, disablement, revocation and Settings retention. Validation is in progress. No completion or live exploit claim.
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
kayg/calternal#787
No description provided.