Is pandas safe?
- Python shell/command execution
- Unsafe deserialization
- Python dynamic code execution
pandas is an AI python_package analyzed by SkillTotal's deterministic static scanner. The scan found no malicious indicators, though 6 risky constructs are reported for review. It can: dynamic code execution, filesystem read, filesystem write, network egress and shell execution — capabilities are what the code can do, not a verdict on intent. Risk score 20/100 (low).
pandas 3.0.3
Automated static-analysis result. It can contain false positives and false negatives, and is not a claim about the intent of pandas's authors. Report a false positive.
Findings (6)
It loads data with a format that can rebuild arbitrary objects (e.g. pickle, or unsafe YAML).
return pickle.load(handles.handle)
Why it matters: Feeding such a loader untrusted data can execute code hidden inside that data.
Fix: Deserialize untrusted data with a safe format/loader: JSON, or yaml.safe_load / Loader=SafeLoader. Reserve pickle/marshal for data you fully control.
The code turns strings into live code at runtime (eval / new Function / exec).
return str(CreateTable(self.table).compile(self.pd_sql.con))
Why it matters: If those strings aren't fixed and trusted, they become a way to run arbitrary code.
Fix: Avoid evaluating dynamically constructed code; if unavoidable, ensure the input is a trusted constant and never derived from external data.
The component can run operating-system commands or spawn processes.
raw_locales = subprocess.check_output(["locale", "-a"])
process = subprocess.Popen(
[command, *args],
cwd=cwd,
env=env,
stdout=subprocess.PIPE,
stderr=(subprocess.PIPE if hide_stderr else None),
**pop …with subprocess.Popen(
["pbcopy", "w"], stdin=subprocess.PIPE, close_fds=True
) as p:with subprocess.Popen(
["pbpaste", "r"], stdout=subprocess.PIPE, close_fds=True
) as p:with subprocess.Popen(
["xclip", "-selection", selection], stdin=subprocess.PIPE, close_fds=True
) as p:with subprocess.Popen(
["xclip", "-selection", selection, "-o"],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
close_fds=True,
) as p:with subprocess.Popen(
["xsel", selection_flag, "-i"], stdin=subprocess.PIPE, close_fds=True
) as p:with subprocess.Popen(
["xsel", selection_flag, "-o"], stdout=subprocess.PIPE, close_fds=True
) as p:subprocess.check_call(args, close_fds=True)
p = subprocess.Popen(args, stdin=subprocess.PIPE, close_fds=True)
p = subprocess.Popen(args, stdout=subprocess.PIPE, close_fds=True)
with subprocess.Popen(
[
"qdbus",
"org.kde.klipper",
"/klipper",
"setClipboardContents",
text.encode(ENCODING),
],
stdin=sub …with subprocess.Popen(
["qdbus", "org.kde.klipper", "/klipper", "getClipboardContents"],
stdout=subprocess.PIPE,
close_fds=True,
) as p:with subprocess.Popen(["clip.exe"], stdin=subprocess.PIPE, close_fds=True) as p:
with subprocess.Popen(
["powershell.exe", "-command", "Get-Clipboard"],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
close_fds=True,
) as p:Why it matters: Powerful and often legitimate — confirm the commands aren't built from untrusted input.
Fix: Confirm the command and its arguments are fully controlled and not derived from untrusted input; avoid shell=True.
The component reads files from disk.
with open(pxifile, encoding="utf-8") as f:
with open(versionfile_abs, encoding="utf-8") as fobj:
with open("/dev/clipboard", encoding="utf-8") as fd:handle = open(
handle,
ioargs.mode,
encoding=ioargs.encoding,
errors=errors,
newline="",
)handle = open(handle, ioargs.mode)
handle = open(handle, "rb")
kwargs["open_with"] = lambda path, _: fsspec.open(
path, "wb", **(storage_options or {})
).open()buf = self._read_bytes(const.align_1_offset, const.align_1_length)
buf = self._read_bytes(const.align_2_offset, const.align_2_length)
buf = self._read_bytes(const.endianness_offset, const.endianness_length)
buf = self._read_bytes(const.encoding_offset, const.encoding_length)[0]
return self._read_bytes(offset, 1)[0]
subheader_signature = self._read_bytes(subheader_offset, self._int_length)
buf = self._read_bytes(offset, text_block_size)
buf = self._read_bytes(offset1, self._lcp)
buf = self._read_bytes(offset1, self._lcp)
buf = self._read_bytes(offset1, self._lcp)
buf = self._read_bytes(offset1, self._lcs)
Why it matters: Usually legitimate, but worth confirming it can't be steered into reading sensitive files.
Fix: Confirm which files are read and that paths cannot be influenced by untrusted input to reach sensitive locations.
The component writes or deletes files on disk.
with open(outfile, "w", encoding="utf-8") as f:
with open(path, "w", encoding="utf-8") as file:
with open(buf, "w", encoding="utf-8") as f:
with open("/dev/clipboard", "w", encoding="utf-8") as fd:with open(buf, "w", encoding=encoding, newline="") as f:
os.unlink(self._fname)
self._write_bytes(vl.generate_value_label(self._byteorder))
self._write_bytes(struct.pack("b", 114))self._write_bytes(struct.pack(byteorder + "h", self.nvar)[:2])
self._write_bytes(struct.pack(byteorder + "i", self.nobs)[:4])
self._write_bytes(self._null_terminate_bytes(_pad_bytes("", 80)))self._write_bytes(
self._null_terminate_bytes(_pad_bytes(data_label[:80], 80))
)self._write_bytes(self._null_terminate_bytes(ts))
self._write_bytes(struct.pack("B", typ))self._write_bytes(records.tobytes())
self._write_bytes(bytes("<stata_dta>", "utf-8"))self._write_bytes(self._tag(bio.getvalue(), "header"))
self._write_bytes(self._tag(bio.getvalue(), "map"))
self._write_bytes(self._tag(bio.getvalue(), "variable_types"))
self._write_bytes(self._tag(bio.getvalue(), "varnames"))
self._write_bytes(self._tag(b"\x00" * sort_size * (self.nvar + 1), "sortlist"))
self._write_bytes(self._tag(bio.getvalue(), "formats"))
self._write_bytes(self._tag(bio.getvalue(), "value_label_names"))
self._write_bytes(self._tag(bio.getvalue(), "variable_labels"))
self._write_bytes(self._tag(bio.getvalue(), "variable_labels"))
Why it matters: Usually legitimate, but worth confirming the paths can't be controlled by untrusted input.
Fix: Confirm which files are written/deleted and that paths cannot be influenced by untrusted input.
The component makes outbound network requests.
from urllib.parse import (
urljoin,
urlparse as parse_url,
uses_netloc,
uses_params,
uses_relative,
)return parse_url(url).scheme in _VALID_URLS
import urllib.request
return urllib.request.urlopen(*args, **kwargs) # noqa: TID251
import urllib.request
req_info = urllib.request.Request(filepath_or_buffer, headers=storage_options)
from urllib.request import pathname2url
return urljoin("file:", pathname2url(path))Why it matters: Usually legitimate, but confirm the destinations are expected and no sensitive data leaves.
Fix: Confirm the destination hosts are expected and that no sensitive data is sent off-host.
Check your own component
Run the same evidence-backed scan on any MCP server, agent skill, or package.
Scan your own componentOr get notified if this component's risk changes:
How we determine this: deterministic static analysis (regex + AST), evidence-anchored, no code execution. Methodology →