ticket uses the provided ticket ID directly when building filesystem paths and does not reject path traversal sequences like ../.
In ticket:105, ticket_path() constructs:
local exact="$TICKETS_DIR/${id}.md"
Because id is not validated, an input like ../secret resolves to: .tickets/../secret.md which escapes the .tickets/ directory.
This path is then used by multiple commands, including:
- show for reads
- add-note for appends
- status for in-place modification
- the bundled edit plugin for opening files
Impact
A caller can read or modify files outside .tickets/ by supplying a crafted ticket ID. This is especially relevant if ticket is used by automation, shell scripts, or AI agents that may pass user-influenced input.
Examples:
- ticket show ../CLAUDE
- ticket add-note ../README 'text'
- ticket edit ../CLAUDE
Expected behavior
Ticket IDs should be constrained to valid ticket identifiers and must not allow path separators or traversal. Resolved paths should be guaranteed to remain within TICKETS_DIR.
- Reject IDs containing /, \, .., or other path traversal patterns.
- Canonicalize the resolved path and verify it is still under TICKETS_DIR before reading or writing.
- Apply the same validation in bundled plugins such as ticket-edit.
- Add regression tests covering traversal attempts for show, status, add-note, and edit.
ticketuses the provided ticket ID directly when building filesystem paths and does not reject path traversal sequences like ../.In ticket:105, ticket_path() constructs:
Because id is not validated, an input like ../secret resolves to:
.tickets/../secret.mdwhich escapes the .tickets/ directory.This path is then used by multiple commands, including:
Impact
A caller can read or modify files outside .tickets/ by supplying a crafted ticket ID. This is especially relevant if ticket is used by automation, shell scripts, or AI agents that may pass user-influenced input.
Examples:
Expected behavior
Ticket IDs should be constrained to valid ticket identifiers and must not allow path separators or traversal. Resolved paths should be guaranteed to remain within TICKETS_DIR.