{"record":{"id":"db8965a116b699ec","repo":"apache/seatunnel","slug":"python-source-runs-unsandboxed-external-code-reso","errorCode":null,"errorMessage":"Python source runs unsandboxed external code. Resolved executable='{}', scriptOrigin='python.script.path={}', guarded by system properties '{}','{}'.","messagePattern":"Python source runs unsandboxed external code\\. Resolved executable='(.+?)', scriptOrigin='python\\.script\\.path=(.+?)', guarded by system properties '(.+?)','(.+?)'\\.","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"seatunnel-connectors-v2/connector-python/src/main/java/org/apache/seatunnel/connectors/seatunnel/python/source/PythonSourceReader.java","lineNumber":132,"sourceCode":"        this.sourceConfig = sourceConfig;\n        this.catalogTable = catalogTable;\n        this.readerContext = readerContext;\n        this.deserializationSchema = createDeserializationSchema(sourceConfig, catalogTable);\n        this.recentStderrLines = new ArrayDeque<>(STDERR_HISTORY_LIMIT);\n        this.stdoutLines = new ArrayBlockingQueue<>(STDOUT_QUEUE_CAPACITY);\n    }\n\n    @Override\n    public void open() throws Exception {\n        synchronized (lifecycleLock) {\n            if (closeRequested) {\n                throw new IOException(\"Python source reader has already been closed\");\n            }\n        }\n        Path scriptPath = validateScriptPath().toAbsolutePath().normalize();\n        Path resolvedExecutable =\n                PythonSourceExecutionPolicy.resolveExecutable(sourceConfig.getPythonExecutable());\n        LOG.warn(\n                \"Python source runs unsandboxed external code. Resolved executable='{}', scriptOrigin='python.script.path={}', guarded by system properties '{}','{}'.\",\n                resolvedExecutable,\n                scriptPath,\n                PythonSourceExecutionPolicy.PYTHON_SOURCE_ENABLED_PROPERTY,\n                PythonSourceExecutionPolicy.PYTHON_ALLOWED_EXECUTABLES_PROPERTY);\n        ProcessBuilder processBuilder =\n                new ProcessBuilder(resolvedExecutable.toString(), scriptPath.toString());\n        configureWorkingDirectory(processBuilder, scriptPath);\n\n        synchronized (lifecycleLock) {\n            if (closeRequested) {\n                throw new IOException(\"Python source reader has already been closed\");\n            }\n            try {\n                this.process = processBuilder.start();\n            } catch (IOException e) {\n                throw new IOException(\n                        \"Failed to start python source process with executable [\"","sourceCodeStart":114,"sourceCodeEnd":150,"githubUrl":"https://github.com/apache/seatunnel/blob/cf67b549a7a6c35fa0beb12d83c62892427ea919/seatunnel-connectors-v2/connector-python/src/main/java/org/apache/seatunnel/connectors/seatunnel/python/source/PythonSourceReader.java#L114-L150","documentation":"The Python source reader executes external Python code without sandboxing. At open() it resolves the configured executable, validates the script path, and logs this warning explicitly stating the risk and which system-property guards (enable flag and allowed-executables list) apply to this source.","triggerScenarios":"PythonSourceReader.open() is called and the reader starts the Python process; logged every time the source opens, showing resolvedExecutable, the python.script.path value, and the two guard properties PYTHON_SOURCE_ENABLED_PROPERTY and PYTHON_ALLOWED_EXECUTABLES_PROPERTY.","commonSituations":"Security review of jobs using the Python source; deployments where the configured executable could be swapped for an arbitrary interpreter; running untrusted scripts in shared clusters.","solutions":["Set the guard system properties explicitly (enable property and allowed-executables allowlist) to restrict which executables may run","Point python.script.path at a trusted, version-controlled script","Restrict python.script.path and python.executable configs via job validation; avoid running untrusted scripts in shared clusters","Wrap the Python execution in an OS-level sandbox (container/user namespace) if untrusted input must run"],"exampleFix":"// before\n-Dpython.source.allowed.executables=*\n// after\n-Dpython.source.enabled=true -Dpython.source.allowed.executables=/usr/bin/python3","handlingStrategy":"validation","validationCode":"String exe = config.get(\"python.executable\");\nPath script = Paths.get(config.get(\"python.script.path\"));\nif (!Files.exists(script)) throw new IllegalArgumentException(\"script not found: \" + script);\nif (!allowedExecutables.contains(exe)) throw new IllegalArgumentException(\"executable not allowlisted: \" + exe);","typeGuard":"static boolean isAllowlisted(Path executable, Set<String> allowlist) { return executable != null && allowlist.contains(executable.toString()); }","tryCatchPattern":"try { reader.open(); } catch (IOException e) { /* reader closed or script path invalid */ log.error(\"python source open failed\", e); }","preventionTips":["Set the enable and allowed-executables system properties explicitly","Version-control and audit the python script","Run python sources in containers, never on shared bare metal","Restrict python.script.path to a trusted directory"],"tags":["security","python","sandbox"],"backgroundTag":"path-traversal-blocked","analyzedSha":"cf67b549a7a6c35fa0beb12d83c62892427ea919","analyzedAt":"2026-09-10T21:44:55.265Z","contentChangedAt":"2026-09-10T21:44:55.265Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}