{"record":{"id":"cf881ab582ed6ea3","repo":"n8n-io/n8n","slug":"security-violation-detected","errorCode":null,"errorMessage":"Security violation detected","messagePattern":"Security violation detected","errorType":"exception","errorClass":"SecurityViolationError","httpStatus":null,"severity":"error","filePath":"packages/@n8n/task-runner-python/src/_sandbox_callables.py","lineNumber":263,"sourceCode":"        object.__setattr__(self, \"_original\", original)\n        object.__setattr__(self, \"_trust_eligible\", trust_eligible)\n\n    def __call__(self, name, *args, **kwargs):\n        config = object.__getattribute__(self, \"_security_config\")\n        # When trusted, package-initiated imports skip the allowlist; user\n        # imports are always validated. Applies to all package code.\n        trusted = (\n            object.__getattribute__(self, \"_trust_eligible\")\n            and config.allow_transitive_imports\n            and not _import_initiated_by_user_code()\n        )\n        if not trusted:\n            validate = object.__getattribute__(self, \"_validate_import\")\n            check_name, package = _validation_target(name, args, kwargs)\n            is_allowed, error_msg = validate(check_name, config, package)\n            if not is_allowed:\n                assert error_msg is not None\n                raise SecurityViolationError(\n                    message=\"Security violation detected\",\n                    description=error_msg,\n                )\n        original = object.__getattribute__(self, \"_original\")\n        return original(name, *args, **kwargs)\n\n    def __repr__(self) -> str:\n        return \"<built-in function __import__>\"\n\n\nclass _SafeFormat(_HardenedCallable):\n    \"\"\"Hardened wrapper around the format-validation entry point injected into\n    user globals under ``EXECUTOR_SAFE_FORMAT_KEY``.\n\n    The actual implementation lives in a module with sensitive globals, so it\n    is held on a denied slot and only ever invoked through ``__call__`` — user\n    code that reaches this instance cannot read it back out.\n    \"\"\"","sourceCodeStart":245,"sourceCodeEnd":281,"githubUrl":"https://github.com/n8n-io/n8n/blob/5ac6606e81f67bb9534255570cd4e86fd8101eee/packages/@n8n/task-runner-python/src/_sandbox_callables.py#L245-L281","documentation":"Thrown by the Python task runner's _GuardedImport wrapper when an import call targets a module not present in the security allowlist. The wrapper intercepts __import__ and importlib.import_module calls, validates the module name against the configured stdlib and external allowlists, and raises SecurityViolationError if the import is denied. Transitive imports from trusted packages may skip validation if allow_transitive_imports is enabled.","triggerScenarios":"Python user code calls import os, import socket, or importlib.import_module('subprocess') for a module not in the configured allowlist. The _validation_target function resolves the import name, the validate function checks it against the security config's allowlists, and is_allowed returns False with an error message.","commonSituations":"Python Code Node attempts to import a standard library module (os, socket, subprocess) not whitelisted. Importing a third-party package (e.g. requests) that the administrator hasn't added to the external allowlist. An allowed package internally imports a denied dependency when allow_transitive_imports is False.","solutions":["Add the module to the Python runner allowlist via the appropriate environment variable (PYTHON_FUNCTION_ALLOW_EXTERNAL or equivalent config).","Enable allow_transitive_imports if a trusted package's internal imports are being blocked.","Refactor to use an allowed alternative module or the n8n HTTP Request node instead of importing directly.","Check the exact error_msg in the SecurityViolationError description to see which module was denied."],"exampleFix":"# before — Python user code\nimport socket  # blocked if not in allowlist\n\n# after — add to env config\n# Set: PYTHON_FUNCTION_ALLOW_EXTERNAL=socket\n# Then: import socket  # now allowed","handlingStrategy":"validation","validationCode":"# Check if a module is in the allowlist before importing\nimport os\n\nALLOWLIST = set(os.environ.get('PYTHON_FUNCTION_ALLOW_EXTERNAL', '').split(','))\n\ndef is_import_allowed(module_name: str) -> bool:\n    return '*' in ALLOWLIST or module_name in ALLOWLIST\n\nif not is_import_allowed('socket'):\n    raise ValueError('socket is not in the allowlist')","typeGuard":null,"tryCatchPattern":"from _sandbox_callables import SecurityViolationError\n\ntry:\n    import socket\nexcept SecurityViolationError:\n    # handle gracefully — use HTTP Request node or allowed alternative\n    pass","preventionTips":["Pre-register all required modules in the Python runner's allowlist environment variables.","Avoid importing security-sensitive standard library modules (os, socket, subprocess) in user code.","If transitive imports from trusted packages are blocked, consider enabling allow_transitive_imports."],"tags":["task-runner","python","security","sandbox","import","configuration"],"backgroundTag":null,"analyzedSha":"5ac6606e81f67bb9534255570cd4e86fd8101eee","analyzedAt":"2026-08-12T05:26:35.080Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}