{"record":{"id":"10e228da74a06e0a","repo":"ComposioHQ/composio","slug":"refusing-to-build-a-path-from-an-unsafe-label","errorCode":null,"errorMessage":"Refusing to build a path from an unsafe {label}: {value!r}. Expected only letters, digits, underscores, and hyphens (pattern {SAFE_COMPONENT_REGEX.pattern}).","messagePattern":"Refusing to build a path from an unsafe (.+?): (.+?)\\. Expected only letters, digits, underscores, and hyphens \\(pattern (.+?)\\)\\.","errorType":"validation","errorClass":"UnsafePathComponentError","httpStatus":null,"severity":"error","filePath":"python/composio/utils/safe_path.py","lineNumber":130,"sourceCode":"            f\"or a drive letter: {value!r}\"\n        )\n\n    if len(value) > MAX_COMPONENT_LENGTH:\n        raise UnsafePathComponentError(\n            f\"Refusing to build a path from a {label} longer than \"\n            f\"{MAX_COMPONENT_LENGTH} characters: {value[:32]!r}... \"\n            f\"({len(value)} characters)\"\n        )\n\n    # `.` and `..` are excluded by the regex (no `.` in the character class),\n    # as are NUL bytes and every separator. The explicit checks above exist to\n    # produce a precise error message rather than a generic pattern mismatch.\n    #\n    # `fullmatch`, not `match`: in a `match`, `$` also matches just before a\n    # single trailing newline, so `\"GMAIL\\n\"` would satisfy `^[A-Za-z0-9_-]+$`\n    # and reach the filesystem with a control character in the name.\n    if not SAFE_COMPONENT_REGEX.fullmatch(value):\n        raise UnsafePathComponentError(\n            f\"Refusing to build a path from an unsafe {label}: {value!r}. \"\n            f\"Expected only letters, digits, underscores, and hyphens \"\n            f\"(pattern {SAFE_COMPONENT_REGEX.pattern}).\"\n        )\n\n    if value.upper() in WINDOWS_RESERVED_NAMES:\n        raise UnsafePathComponentError(\n            f\"Refusing to build a path from a reserved device name as {label}: {value!r}\"\n        )\n\n    return value\n\n\ndef safe_basename(name: str, *, label: str = \"filename\") -> str:\n    \"\"\"Collapse an untrusted filename to a bare, writable basename.\n\n    Filenames need their own validator: :func:`assert_safe_path_component`\n    forbids ``.``, which nearly every real filename contains. This applies the","sourceCodeStart":112,"sourceCodeEnd":148,"githubUrl":"https://github.com/ComposioHQ/composio/blob/64b1b85502b1beeb2379e6c9e8bf1104504fa637/python/composio/utils/safe_path.py#L112-L148","documentation":"assert_safe_path_component only accepts letters, digits, underscores, and hyphens (^[A-Za-z0-9_-]+$ via fullmatch). Anything else — dots, spaces, unicode, trailing newline — is rejected. fullmatch (not match) is used so 'GMAIL\\n' can't sneak a control character past a trailing-$ match.","triggerScenarios":"secure_join(root, 'my.tool'), secure_join(root, 'café'), or any slug with punctuation/whitespace/control characters.","commonSituations":"Backend tool slugs containing dots or non-ASCII characters; user-supplied names used as directory components; values with trailing newlines from sloppy string handling.","solutions":["Normalize the identifier: strip whitespace and replace disallowed characters with '_'","If the value is user-supplied, enforce the slug pattern at input time","Use safe_basename/secure_basename_join instead when the value is a filename that legitimately contains dots"],"exampleFix":"# before\nsecure_join(root, 'gmail.send_email')\n# after\nimport re\nslug = re.sub(r'[^A-Za-z0-9_-]', '_', 'gmail.send_email')\nsecure_join(root, slug)","handlingStrategy":"validation","validationCode":"import re\nSAFE = re.compile(r'^[A-Za-z0-9_-]+$')\ndef is_clean_component(v):\n    return isinstance(v, str) and bool(SAFE.fullmatch(v))","typeGuard":"import re\ndef is_slug_safe(v: str) -> bool:\n    return bool(re.fullmatch(r'[A-Za-z0-9_-]+', v))","tryCatchPattern":"from composio.exceptions import UnsafePathComponentError\nimport re\ntry:\n    p = secure_join(root, slug)\nexcept UnsafePathComponentError:\n    p = secure_join(root, re.sub(r'[^A-Za-z0-9_-]', '_', slug))","preventionTips":["Enforce the slug pattern on user input at the boundary","Use safe_basename for filenames that legitimately contain dots"],"tags":["path-validation","security","python"],"backgroundTag":"unsafe-path-characters","analyzedSha":"64b1b85502b1beeb2379e6c9e8bf1104504fa637","analyzedAt":"2026-08-28T15:39:33.623Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}