SkillTotal

Is huggingface-hub safe?

No malicious indicators - review capabilities before installing
Notable — review in context (capabilities are not malware):
  • Python shell/command execution
  • Python filesystem read
  • Python filesystem write/delete

huggingface_hub-1.27.0 is an AI python_package analyzed by SkillTotal's deterministic static scanner. The scan found no malicious indicators, though 5 risky constructs are reported for review. It can: delegated authentication, filesystem read, filesystem write, network egress and shell execution — capabilities are what the code can do, not a verdict on intent. Risk score 0/100 (low).

huggingface_hub-1.27.0 1.27.0

python_package · pypi:huggingface-hub
LOW
0
/ 100 risk score
Snapshot · scanned Aug 8, 2026 · huggingface_hub-1.27.0@1.27.0 · engine 0.38.1 / ruleset 42

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.

Capabilities — what this component can do (not a risk score):
delegated authenticationfilesystem readfilesystem writenetwork egressshell execution

Behavioral traits

How this component maps to the CSA agentic threat model. Descriptive — it never affects the risk score.

Execution authority
Tool Access Control / Direct Tool Access
Filesystem reach
Tool Execution Context
Network egress
Interaction & Communication / Direct Communication
Delegated authentication
Tool Execution Context / User Delegated Credentials

Findings (5)

HIGHPython shell/command executionST-SHELL-PY

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,
        )
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", "--claude"])
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.

MEDIUMPython filesystem readST-FS-PY-READ

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(self.path_or_fileobj, "rb") as file:
self._write_ranges(path, Path(local_path).read_bytes(), mode)
with open(local_path, "rb") as f:
with open(path, encoding="utf-8") as f:
env_map.update(load_dotenv(Path(env_file).read_text(), environ=extended_environ))
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")
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(paths.file_path, "rb") as f:
return ResolvedRevision(resolved=ref_path.read_text().strip(), initial=revision)
content=relpath_to_abspath["README.md"].read_text(encoding="utf8"),

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.

MEDIUMPython filesystem write/deleteST-FS-PY-WRITE

The component writes or deletes files on disk.

with open(plan_file, "w") as f:
tag_path.write_text(CACHEDIR_TAG_CONTENT)
with open(local_path, "wb") as f:
with open(local_path, "wb") as f:
path.write_text(_completion_script("fish"))
(install_dir / "SKILL.md").write_text(content, encoding="utf-8")
manifest_path.write_text(json.dumps(data, indent=2, sort_keys=True))
shutil.rmtree(extension_dir, ignore_errors=True)
executable_path.write_bytes(binary)
shutil.copytree(central_skill_path, link_path)
shutil.copytree(temp_dir.name, persistent_temp_dir, dirs_exist_ok=True)
shutil.move(abs_src, abs_dst, copy_function=_copy_no_matter_what)
shutil.copyfile(abs_src, abs_dst)
tmp_path.write_text(commit_hash)

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.

MEDIUMPython network egressST-NET-PY

The component makes outbound network requests.

self.client = httpx.Client(
            base_url=f"{base_host}/--replicas/+{replica_hash}",
            headers=build_hf_headers(token=token),
            timeout=CLIENT_TIMEOUT,
        )
redirect_uri = f"{login_uri}?{urllib.parse.urlencode(query_params)}"
return RedirectResponse(callback_uri + "?" + urllib.parse.urlencode({"_target_url": redirect_uri}))
target = "/?" + urllib.parse.urlencode(request.query_params)
self._client = httpx.Client(
            headers={
                "Authorization": f"Bearer {self._auth_token}",
                "X-Sandbox-Token": sandbox_token,
            },
            limits=httpx.Limits(max_connections=max_connectio …
limits=httpx.Limits(max_connections=max_connections, max_keepalive_connections=max_connections),
timeout = kwargs.pop("timeout", httpx.Timeout(60.0, connect=10.0))
timeout = kwargs.pop("timeout", httpx.Timeout(70.0, connect=10.0))  # server pings every 15s
response = self._client.get(self.base_url + "/health", timeout=httpx.Timeout(5.0))
self.base_revision_quoted = quote(self.revision, safe="")
self.commit_revision_quoted = quote(pr.git_reference, safe="")
from urllib.parse import urlsplit
ssh_url = urlsplit(job.status.ssh_url)
from urllib.parse import urlsplit
urlsplit(_HF_DEFAULT_ENDPOINT).hostname,
urlsplit(_HF_DEFAULT_STAGING_ENDPOINT).hostname,
urlsplit(ENDPOINT).hostname,
from httpx import HTTPError, Response

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.

LOWDelegated authentication (OAuth 2.0 / OIDC)ST-AUTH-DELEGATED

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. (12 occurrence(s) shown as evidence).

"authlib>=1.3.2",  # minimum version to include https://github.com/lepture/authlib/pull/644
"httpx",  # required for authlib but not included in its dependencies
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",
_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 component

How we determine this: deterministic static analysis (regex + AST), evidence-anchored, no code execution. Methodology →