Skip to content

v0.18.4

Choose a tag to compare

@webpatser webpatser released this 24 Oct 13:04
· 11 commits to main since this release

Security

  • Dashboard payloads no longer show secrets stored on the serialized job. PayloadSanitizer only matched key=value / key: value text, so properties inside the PHP-serialized data.command (s:8:"password";s:7:"hunter2";) were rendered verbatim to every dashboard user. Serialized commands (including nested chained jobs) are now walked property by property: public, protected and private properties with a secret-sounding name show ***, string leaves get the usual pattern redaction, and every s:N length is recomputed so the result is still valid serialized data. Unparseable serialized data is hidden entirely. Authorization: Basic <base64> credentials are redacted too (previously only the word Basic was), as is a standalone Basic <base64> that decodes to user:pass.
  • Exception messages, traces and job events are redacted in the dashboard. The dead-letter screen, the inspector (exception tab and timeline) and the legacy job inspector's Livewire snapshot rendered exception messages and traces without passing them through PayloadSanitizer.

Fixed

  • igbinary payloads are only decoded when torque.serializer is igbinary. StreamQueue::decodePayload() used to hand any stream entry that began with the igbinary header to igbinary_unserialize(), whatever the configured serializer. It now requires serializer === 'igbinary' and an array type tag after the header, and isValidPayload() sniffs the header (and validates JSON with json_validate()) instead of fully decoding. Both take an optional $serializer argument that defaults to torque.serializer. Behaviour change: on a JSON-configured install, leftover igbinary entries from a previous TORQUE_SERIALIZER=igbinary run are never unserialized; the worker moves them, undecoded, to the dead-letter stream with reason serializer_mismatch instead of running them.
  • The master PID temp file can no longer be redirected through a symlink. writePidFile() wrote storage/torque.pid.<pid>.tmp with file_put_contents(), which follows symlinks, so a local user who could write to storage/ could plant a link there and have the master truncate another file (.env, say). The temp file is now created with fopen('x') (O_CREAT|O_EXCL, group-writable via umask instead of a chmod()), a stale or planted temp path is unlinked first, and the master lock file path is refused when it is a symlink.
  • Queue enumeration no longer uses KEYS. StreamQueue::allQueueNames(), behind allPendingJobs(), allReservedJobs() and allDelayedJobs() and so every dashboard load, ran KEYS {prefix}*, which blocks Redis for the whole sweep on a large keyspace. It now walks the prefix with incremental SCAN ... COUNT 500 (glob characters in the prefix are escaped).