Repository navigation
[v5r0] Backport: secure JSON state encoding + DEncode depth check fix - #811
Merged
Merged
Conversation
DEncode uses a custom binary format (similar to bencode) with no protection against deeply nested structures or untrusted input. Changes: - Use json.dumps() for encoding app state (web_saveAppState) - Add _safeDecode() helper that tries JSON first, falls back to DEncode only for backward compatibility with legacy stored data - Add decompressed size limit (5MB) to prevent zip bombs - Add _checkDEncodeDepth() to prevent DoS via deeply nested structures - Validate decoded types to prevent complex object injection - Remove print() statement leaking user info in web_listPublicDesktopStates - Fix double-encoding bug in web_changeView - Remove unused 'random' import
_checkDEncodeDepth counted every d/l/t/e byte in the stream as structure, including characters inside DEncode string payloads (s<len>:payload), whose content is arbitrary bytes. Legacy stored states whose payload contained enough container-like characters falsely triggered 'DEncode data exceeds maximum nesting depth (50)' and 'DEncode data has unbalanced nesting', turning valid data into HTTP 500 errors in web_listAppState. Walk the DEncode stream token by token instead, skipping string payloads and scalar values, so that only real containers (d/l/t) contribute to the nesting depth. Malformed data is now rejected earlier with clearer messages, and genuinely deep nesting is still rejected, keeping the DoS guard intact. Also make web_listAppState skip vars that cannot be decoded instead of failing the whole listing.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Backport of the UPHandler state-decoding security hardening to
rel-v5r0, in two cherry-picked commits:fix: replace insecure DEncode deserialization with JSON(cherry-picked from integration) —rel-v5r0was still calling the recursiveDEncode.decode()directly on legacy data with no decompressed-size limit and no nesting-depth guard. This commit adds the JSON-first_safeDecode()with a 5 MB decompressed-size limit (zip-bomb protection) and_checkDEncodeDepth()(DoS protection against deeply nested DEncode structures).fix: DEncode depth check false positives on string payloads— corrects_checkDEncodeDepth, which counted everyd/l/t/ebyte as structure, including characters inside DEncode string payloads (s<len>:payload, arbitrary bytes). Valid legacy states whose payload contains enough container-like characters falsely raisedDEncode data exceeds maximum nesting depth (50)/DEncode data has unbalanced nesting, producing HTTP 500 inweb_listAppState(observed in production). The checker now walks the DEncode stream token by token, skipping string payloads and scalars, so only real containers contribute to depth. Genuinely deep nesting is still rejected; malformed data is rejected earlier with clearer messages.web_listAppStatealso now logs and skips undecodable vars instead of failing the whole listing.The resulting
UPHandler.pyis byte-identical to the version proposed forintegrationin #810.Evidence
DEncode.decode()on arbitrary deeply nested legacy data → recursion near Python's recursion limit (~1000 frames) from a single authenticated request; and with the naive depth check (integration),DEncode.encode({"data": "d"*50})(true nesting depth 2) raisedValueError: DEncode data exceeds maximum nesting depth (50)→ HTTP 500.DIRAC.Core.Utilities.DEncode;b"d"*200 + b"e"*200still rejected with the depth error; unbalanced and malformed streams rejected.Merge Danger
Door: two-way
Blast Radius: UPHandler only
Affects only decoding (and, for newly saved states, JSON encoding) of application/desktop states in the user profile. Legacy states remain readable; newly saved states are pure JSON. Deployment note: sites running v5r0-era WebAppDIRAC that upgrade will decode both old (DEncode) and new (JSON) states.