Is Last30Days Skill safe?
- Python shell/command execution
- Python filesystem read
- Python filesystem write/delete
last30days-skill 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: filesystem read, filesystem write, mcp tools detected, network egress and shell execution — capabilities are what the code can do, not a verdict on intent. Risk score 0/100 (low).
last30days-skill 3.21.0
Automated static-analysis result. It can contain false positives and false negatives, and is not a claim about the intent of Last30Days Skill'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 (5)
The component can run operating-system commands or spawn processes.
subprocess.run(cmd, cwd=ROOT, check=True)
result = subprocess.run(
cmd,
cwd=repo_dir,
env=env,
capture_output=True,
text=True,
timeout=timeout_seconds,
check=False,
)subprocess.run(
["git", "worktree", "add", "--detach", str(worktree_dir), rev],
cwd=REPO_ROOT,
check=True,
capture_output=True,
text=True,
)subprocess.run(
["git", "worktree", "remove", "--force", str(path)],
cwd=REPO_ROOT,
check=False,
capture_output=True,
text=True,
)result = subprocess.run(
["security", "find-generic-password", "-w", "-s", service_name],
capture_output=True,
text=True,
timeout=10,
)result = subprocess.run(
[
"openssl", "enc", "-aes-128-cbc", "-d",
"-K", hex_key,
"-iv", CHROME_IV_HEX,
"-nopad",
],
input=ciphertext, …completed = subprocess.run(
[pdftotext, str(path), "-"],
capture_output=True,
check=True,
text=True,
timeout=20,
)result = subprocess.run(
[security, "find-generic-password",
"-a", account,
"-s", service,
"-w"],
capture_output=True, text=True, timeout=5,
)result = subprocess.run(
[pass_bin, "show", f"{prefix}{key}"],
capture_output=True, text=True, timeout=5,
encoding="utf-8", errors="replace",
)result = subprocess.run(
["gh", "auth", "token"],
capture_output=True, text=True, timeout=5,
)result = subprocess.run(
[binary, "-p", prompt, "--permission-mode", "bypassPermissions"],
capture_output=True,
text=True,
timeout=timeout,
cwd=workdir, …proc = subprocess.run(
command,
capture_output=True,
text=True,
timeout=timeout,
)proc = subprocess.run(
command,
capture_output=True,
text=True,
timeout=timeout,
)proc = subprocess.run(
["brew", "install", "yt-dlp"],
capture_output=True, text=True, timeout=120,
)proc = subprocess.run(
[npx, "-y", PRINTING_PRESS_NPM, "install", slug, "--cli-only"],
capture_output=True, text=True, timeout=DIGG_INSTALL_TIMEOUT,
)subprocess.run(["pbcopy"], input=user_code.encode(), check=True, timeout=5)
proc = subprocess.Popen(
list(cmd),
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True,
encoding="utf-8",
errors="replace",
preexec_fn=preexec,
env=env,
)result = subprocess.run(
["xurl", "auth", "status"],
capture_output=True,
text=True,
timeout=10,
)result = subprocess.run(
["xurl", "search", query, "-n", str(max_results), "--auth", "app"],
capture_output=True,
text=True,
timeout=30,
)return subprocess.run(
cmd,
cwd=REPO_ROOT,
env=env,
text=True,
capture_output=True,
timeout=timeout,
check=True,
)*subprocess.run(
[
"rg",
"--files",
"skills/last30days/scripts",
"tests",
"-g",
"*.py", …result = subprocess.run(
[
sys.executable,
str(SCRIPT_DIR / "last30days.py"),
search_term,
"--emit=json",
"--json-profile=raw",
"--q …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.
text = PYPROJECT.read_text(encoding="utf-8")
text = path.read_text(encoding="utf-8")
text = SKILL_MD.read_text(encoding="utf-8")
data = json.loads(path.read_text(encoding="utf-8"))
data = json.loads(path.read_text(encoding="utf-8"))
text = UV_LOCK.read_text(encoding="utf-8")
with open(path, encoding="utf-8") as f:
rows = json.loads(EVAL_TOPICS_FILE.read_text())
payload = json.loads(cache_file.read_text())
if not engine.exists() or "--json-profile" in engine.read_text(encoding="utf-8"):
payload = json.loads(metrics_path.read_text()) if metrics_path.exists() else {lines = summary_path.read_text().splitlines() if summary_path.exists() else ["# Search Quality Evaluation", ""]
rows = json.loads(path.read_text())
return Path(path).expanduser().read_text(encoding="utf-8")
with open(plan_str, encoding="utf-8") as f:
payload = json.loads(cache_path.read_text(encoding="utf-8"))
payload = json.loads(cache_path.read_text(encoding="utf-8"))
marker_found = generated_marker in existing_path.read_text(encoding="utf-8")
generated = html_render.LIBRARY_BRIEF_MARKER in path.read_text(
encoding="utf-8"
)with open(plan_str, encoding="utf-8") as f:
return "microsoft" in Path("/proc/version").read_text().lower()payload = json.loads(path.read_text(encoding="utf-8"))
raw = path.read_text(encoding="utf-8")
raw = file_path.read_text(encoding="utf-8")
payload = json.loads(path.read_text(encoding="utf-8"))
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.
path.write_text(updated, encoding="utf-8")
SKILL_MD.write_text(text3, encoding="utf-8")
path.write_text(json.dumps(data, indent=2) + "\n", encoding="utf-8")
path.write_text(json.dumps(data, indent=2) + "\n", encoding="utf-8")
UV_LOCK.write_text(updated, encoding="utf-8")
with open(path, "w", encoding="utf-8") as f:
cache_file.write_text(json.dumps(payload, indent=2))
(output_dir / "metrics.json").write_text(json.dumps(payload, indent=2))
(output_dir / "summary.md").write_text("\n".join(lines) + "\n")metrics_path.write_text(json.dumps(payload, indent=2))
summary_path.write_text("\n".join(lines).rstrip() + "\n")_publish_metadata_path(html_path).write_text(json.dumps(payload, indent=2), encoding="utf-8")
(target / "last-run.json").write_text(json.dumps(payload, indent=2))
report_cache_path.write_text(json.dumps(cache_payload, indent=2))
cache_path.write_text(json.dumps(payload, indent=2), encoding="utf-8")
pending_path.write_text(json.dumps(payload, indent=2), encoding="utf-8")
feed_path.write_text(feed_xml, encoding="utf-8")
index_path.write_text(index_html, encoding="utf-8")
feed_path.write_text(
feed.render_atom(
entries,
library_id=library_id,
entry_urls=entry_urls,
author=feed_author,
),
encoding="utf-8", …index_path.write_text(
html_render.render_library_index(entries, entry_urls=entry_urls),
encoding="utf-8",
)shutil.copyfile(str(db_path), tmp_path)
shutil.copyfile(str(db_path), tmp_path)
path.write_text(json.dumps(payload, indent=2), encoding="utf-8")
path.write_text(raw, encoding="utf-8")
shutil.copyfile(store, os.path.join(child_store_dir, store.name))
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.error import HTTPError, URLError
from urllib.request import Request, urlopen
request = Request(
GEMINI_API_URL.format(model=model, api_key=api_key),
data=json.dumps(body).encode("utf-8"),
headers={"Content-Type": "application/json"},
method="POST",
)with urlopen(request, timeout=120) as response:
from urllib.parse import urlparse
parsed = urlparse(url)
expected = urlparse(domain or DEFAULT_DOMAIN)
from urllib.parse import urlencode
url = f"{_resolve_search_url(config)}?{urlencode(params)}"from urllib.parse import urlparse
scheme = urlparse(url).scheme.lower()
import urllib.error
import urllib.request
req = urllib.request.Request(
url, headers=headers or {"User-Agent": "last30days-doctor"}
)with urllib.request.urlopen(req, timeout=timeout) as resp:
import urllib.parse
params = urllib.parse.urlencode({"q": topic, "limit": limit})from urllib.parse import parse_qs, urlencode, urlparse, urlunparse
parsed = urlparse(url.strip().lower())
params = parse_qs(parsed.query)
query = urlencode(clean_params, doseq=True)
return urlunparse((parsed.scheme, netloc, parsed.path.rstrip("/"), "", query, ""))import urllib.error
import urllib.parse
import urllib.request
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.
An MCP tool surface (manifest or tool definitions) was found.
Why it matters: Just context — review which tools it offers and their permissions.
Fix: Review the declared MCP tools and their permissions.
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 →