Is huggingface-hub safe?
- Python shell/command execution
- Python filesystem read
- Python filesystem write/delete
huggingface_hub-2.0.0 is an AI python_package analyzed by SkillTotal's deterministic static scanner. The scan found no malicious indicators, though 4 risky constructs are reported for review. It can: delegated authentication, filesystem read, filesystem write and shell execution — capabilities are what the code can do, not a verdict on intent. Risk score 0/100 (low).
huggingface_hub-2.0.0 2.0.0
Automated static-analysis result. It can contain false positives and false negatives, and is not a claim about the intent of huggingface-hub's authors. Report a false positive.
Behavioral traits
How this component maps to the CSA agentic threat model. Descriptive — it never affects the risk score.
Findings (4)
The component can run operating-system commands or spawn processes.
result = subprocess.run(
[self.binary_path, "-json"],
input=full_query,
capture_output=True,
text=True,
check=False,
)result = subprocess.run(cmd)
return subprocess.call(cmd)
subprocess.run([uv_path, "venv", str(venv_dir)], check=True)
subprocess.run(install_cmd, check=True, timeout=_EXTENSIONS_PIP_INSTALL_TIMEOUT)
return subprocess.call([str(executable_path)] + args)
return subprocess.call(["sh", str(executable_path)] + args)
subprocess.run(
"git config lfs.customtransfer.multipart.path hf".split(),
check=True,
cwd=local_path,
)subprocess.run(
f"git config lfs.customtransfer.multipart.args {LFS_MULTIPART_UPLOAD_COMMAND}".split(),
check=True,
cwd=local_path,
)res = subprocess.run(command, start_new_session=True)
subprocess.call([*_hf_argv(), "skills", "update", DEFAULT_SKILL_ID, "-g"])
return subprocess.run(
command,
capture_output=True,
check=check,
encoding="utf-8",
errors="replace", # if not utf-8, replace char by �
cwd=folder or os.getcwd(),
**kwargs,
)with subprocess.Popen(
command,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
encoding="utf-8",
errors="replace", # if not utf-8, replace char by �
cwd=fold …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(rel_path, "r") as fp:
long_description=open("README.md", "r", encoding="utf-8").read(),with open(filter_file) as f:
with open(plan_file) as f:
with open(self.path_or_fileobj, "rb") as file:
with open(local_path, "rb") as f:
with open(ref_path) as f:
with open(ref_path) as f:
with open(path, encoding="utf-8") as f:
return path.read_text()
existing = path.read_text() if path.exists() else ""
with open(tmp_path, "rb") as f:
parsed = json.loads(local_path.read_text(encoding="utf-8"))
content = (skill_dir / "SKILL.md").read_text(encoding="utf-8")
script=str(local_path), header=parse_uv_script_header(local_path.read_text(encoding="utf-8"))
yield UvScript(script=script, header=parse_uv_script_header(path.read_text(encoding="utf-8")))
return body_file.read_text(encoding="utf-8")
data = json.loads(manifest_path.read_text())
with open(filepath, "rb") as file:
if not ref_path.exists() or commit_hash != ref_path.read_text():
with open(ref_path) as f:
with open(paths.file_path, "rb") as f:
with open(revision_file) as f:
resolved=ref_path.read_text().strip(), initial=revision, repo_id=repo_id, repo_type=repo_type
with open(index_file) as f:
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(plan_file, "w") as f:
os.remove(file_path)
gitignore.write_text("*")tag_path.write_text(CACHEDIR_TAG_CONTENT)
formatter.write_text(line)
path.write_text(_completion_script("fish"))(install_dir / "SKILL.md").write_text(content, encoding="utf-8")
shutil.rmtree(install_dir)
shutil.rmtree(backup_dir)
local_path.write_bytes(response.content)
manifest_path.write_text(json.dumps(data, indent=2, sort_keys=True))
shutil.rmtree(extension_dir)
shutil.rmtree(extension_dir)
shutil.rmtree(extension_dir, ignore_errors=True)
executable_path.write_bytes(binary)
shutil.rmtree(path)
shutil.copytree(central_skill_path, link_path)
shutil.copytree(temp_dir.name, persistent_temp_dir, dirs_exist_ok=True)
with open(path, "w") as f:
os.remove(dst)
shutil.move(abs_src, abs_dst, copy_function=_copy_no_matter_what)
shutil.copyfile(abs_src, abs_dst)
tmp_path.write_text(commit_hash)
shutil.copyfile(cached_path, paths.file_path)
shutil.move(str(src), str(dst), copy_function=_copy_no_matter_what)
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.
An OAuth 2.0 / OpenID Connect delegated-authentication flow was detected (authorization-code / refresh-token / token-exchange grant, an OIDC authorize/discovery endpoint or id_token, or a delegation library). Tools authenticate with the end user's delegated, scoped credentials rather than a long-lived embedded service credential. (11 occurrence(s) shown as evidence).
"authlib>=1.8.0", # first version supporting httpx2
from authlib.integrations.base_client.errors import MismatchingStateError
from authlib.integrations.starlette_client import OAuth
server_metadata_url=constants.OPENID_PROVIDER_URL + "/.well-known/openid-configuration",
"id_token": "FOOBAR",
_TOKEN_EXCHANGE_GRANT_TYPE = "urn:ietf:params:oauth:grant-type:token-exchange"
_ID_TOKEN_TYPE = "urn:ietf:params:oauth:token-type:id_token"
_REFRESH_TOKEN_GRANT_TYPE = "refresh_token"
Fix: Delegated auth is a lower-blast-radius execution context than an embedded static credential. Confirm the requested scopes are minimal and that tokens are never logged or forwarded off-host.
Check your own component
Run the same evidence-backed scan on any MCP server, agent skill, or package.
Scan your own componentHow we determine this: deterministic static analysis (regex + AST), evidence-anchored, no code execution. Methodology →