fix(security): harden Python service boundaries

This commit is contained in:
Alexandre Teixeira
2026-10-06 03:16:54 +01:00
parent da3800b662
commit 3d91ad82cb
32 changed files with 1911 additions and 248 deletions
+70 -9
View File
@@ -63,19 +63,80 @@ INTERNAL_UPLOAD_URL_RE = re.compile(
r"([0-9a-fA-F]{32}(?:\.[A-Za-z0-9]+)?)"
r"(?=$|[\s\"'<>\[\](){},;!?:&#]|\.(?![A-Za-z0-9]))"
)
PDF_SOURCE_UPLOAD_RE = re.compile(
r"<!--\s*pdf(?:_form)?_source\b[^>]*\bupload_id="
r"[\"']([0-9a-fA-F]{32}(?:\.[A-Za-z0-9]+)?)[\"'][^>]*-->",
# `<!--\s*pdf(?:_form)?_source\b[^>]*\bupload_id=["'](id)["'][^>]*-->` and
# `\[Attachment:[^\]\r\n]*\|\s*id=(id)(?:\s*\||\s*\])` are matched by the
# forward-only scanners below. As single regexes, every opener in a run with no
# closing `>` / `]` rescanned to the end of that run: O(n^2) on chat content,
# which is unbounded on persisted assistant output (CodeQL py/polynomial-redos).
_PDF_SOURCE_OPEN_RE = re.compile(r"<!--\s*pdf(?:_form)?_source\b", re.IGNORECASE)
_PDF_SOURCE_ID_RE = re.compile(
r"\bupload_id=[\"']([0-9a-fA-F]{32}(?:\.[A-Za-z0-9]+)?)[\"']",
re.IGNORECASE,
)
ATTACHMENT_REFERENCE_LINE_RE = re.compile(
r"\[Attachment:[^\]\r\n]*\|\s*id="
r"([0-9a-fA-F]{32}(?:\.[A-Za-z0-9]+)?)"
r"(?:\s*\||\s*\])",
_ATTACHMENT_REFERENCE_OPEN_RE = re.compile(r"\[Attachment:", re.IGNORECASE)
_ATTACHMENT_REFERENCE_STOP_RE = re.compile(r"[\]\r\n]")
_ATTACHMENT_REFERENCE_TAIL_RE = re.compile(
r"\|\s*id=([0-9a-fA-F]{32}(?:\.[A-Za-z0-9]+)?)(?:\s*\||\s*\])",
re.IGNORECASE,
)
def _pdf_source_upload_ids(value: str) -> list[str]:
"""IDs from `<!-- pdf_source ... upload_id="<id>" ... -->` comments.
Every opener before the next `>` shares that `>`: the comment matches only
if `--` sits right before it, and then with the last `upload_id=` (the
greedy `[^>]*` backtracks from the right). Otherwise all of those openers
fail together, so the scan resumes after the `>`.
"""
found: list[str] = []
pos = 0
while True:
opener = _PDF_SOURCE_OPEN_RE.search(value, pos)
if opener is None:
return found
close = value.find(">", opener.end())
if close < 0:
return found
if value[close - 2:close] == "--":
last = None
for last in _PDF_SOURCE_ID_RE.finditer(value, opener.end(), close):
pass
if last is not None:
found.append(last.group(1))
pos = close + 1
def _attachment_reference_ids(value: str) -> list[str]:
"""IDs from `[Attachment: name | id=<id> | ...]` reference lines.
The label scan stops at the first `]`/CR/LF, so every opener before that
stop shares it and can only use the last `|` (scanning right to left)
whose tail matches. If none does, all of those openers fail together and
the scan resumes at the stop.
"""
found: list[str] = []
pos = 0
while True:
opener = _ATTACHMENT_REFERENCE_OPEN_RE.search(value, pos)
if opener is None:
return found
stop = _ATTACHMENT_REFERENCE_STOP_RE.search(value, opener.end())
end = stop.start() if stop else len(value)
tail = None
pipe = value.rfind("|", opener.end(), end)
while pipe >= 0:
tail = _ATTACHMENT_REFERENCE_TAIL_RE.match(value, pipe)
if tail is not None:
break
pipe = value.rfind("|", opener.end(), pipe)
if tail is None:
pos = end
else:
found.append(tail.group(1))
pos = tail.end()
def is_valid_upload_id(upload_id: str) -> bool:
"""Return True when *upload_id* matches the canonical uploads.json id format."""
return UPLOAD_ID_RE.fullmatch(upload_id or "") is not None
@@ -110,8 +171,8 @@ def extract_internal_upload_ids(value: Any) -> set[str]:
return set()
return (
set(INTERNAL_UPLOAD_URL_RE.findall(value))
| set(PDF_SOURCE_UPLOAD_RE.findall(value))
| set(ATTACHMENT_REFERENCE_LINE_RE.findall(value))
| set(_pdf_source_upload_ids(value))
| set(_attachment_reference_ids(value))
)