Back to skill

Security audit

naver-news-briefing

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly does what it claims, but its automation output can embed unsafe user text in shell/cron commands and it may store API secrets locally in plaintext outside Windows.

Review any integration-plan, cron, shell, or OpenClaw task text before using it, especially if the request text came from someone else. Prefer interactive credential setup instead of passing secrets on the command line, keep data/config.json and data/watch_state.db out of repositories and shared folders, and verify local file permissions if using this outside Windows.

Vulnerability Patterns
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (2)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/config_store.py:82
Finding

Plaintext API Secret Storage and Command-Line Credential Exposure

Content
View full analysis
Dict[str, str]: plain = str(client_secret or "").strip() if not plain: return {"client_secret": "", "client_secret_enc": "", "client_secret_storage": "plain"} if _is_windows_platform(): encrypted = _dpapi_encrypt_text(plain) if encrypted: return {"client_secret": "", "client_secret_enc": encrypted, "client_secret_storage": "dpapi"} return {"client_secret": plain, "client_secret_enc": "", "client_secret_storage": "plain"} ``` ```python def _write_text_atomic(path: str, text: str) -> None: directory = os.path.dirname(os.path.abspath(path)) or "." os.makedirs(directory, exist_ok=True) fd, tmp_path = tempfile.mkstemp(prefix=".config_", suffix=".tmp", dir=directory) try: with os.fdopen(fd, "w", encoding="utf-8", newline="\n") as f: f.write(text) if not text.endswith("\n"): f.write("\n") f.flush() os.fsync(f.fileno()) os.replace(tmp_path, path) finally: if os.path.exists(tmp_path): os.remove(tmp_path) ``` ```python def set_credentials(client_id: str, client_secret: str, timeout: int = 15) -> Dict[str, Any]: config = load_config() encoded = encode_client_secret_for_storage(client_secret) config["naver_api"].update( { "client_id": str(client_id or "").strip(), "client_secret": encoded["client_secret"], "client_secret_enc": encoded["client_secret_enc"], "client_secret_storage": encoded["client_secret_storage"], "timeout": max(5, min(60, int(timeout))), } ) save_config(co ...[truncated 2228 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/automation_plans.py:235
Finding

Unescaped User Input in Generated Shell Commands and OpenClaw Task Prompts

Content
View full analysis
List[str]: commands: List[str] = [] if plan.query_mode == "group": quoted_queries = " ".join(f'"{query}"' for query in plan.queries) commands.append( f'python scripts/naver_news_briefing.py group-add {plan.name_hint} {quoted_queries} --label "자동 생성 그룹" --context "{plan.raw_request}" --template {plan.template}' ) commands.append(f"python scripts/naver_news_briefing.py brief-multi --group {plan.name_hint} --template {plan.template}") commands.append(f'python scripts/naver_news_briefing.py plan-save "{plan.raw_request}" --as group --name {plan.name_hint}') else: query = plan.primary_query or "" if "monitor" in plan.action: commands.append(f'python scripts/naver_news_briefing.py watch-add {plan.name_hint} "{query}" --template {plan.template}') commands.append(f"python scripts/naver_news_briefing.py watch-check {plan.name_hint} --json") if "briefing" in plan.action: commands.append(f'python scripts/naver_news_briefing.py search "{query}"') commands.append(f'python scripts/naver_news_briefing.py plan-save "{plan.raw_request}" --as watch --name {plan.name_hint}') return commands ``` ```python def build_integration_bundle(raw: str, *, skill_dir: str | Path | None = None, assistant_channel: str = "telegram") -> Dict[str, Any]: plan = parse_automation_request(raw) skill_root = Path(skill_dir).resolve() if skill_dir else Path(__file__).resolve().parents[1] cli_rel = str(skill_root / "scripts" / "naver_news_briefing.py") save_as = "group" if plan.query_mode == "group" else "watch" save_comman ...[truncated 5270 chars]
Remediation
View remediation
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (19)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The supplied code chunk is a configuration/credential storage module, not a Naver News search/briefing/monitoring implementation. It reads and writes a config file, stores Naver API client ID/secret, optionally encrypts the secret with Windows DPAPI, and returns runtime credentials. While credential persistence is a supporting detail for a news skill, this chunk does not implement any of the declared user-facing capabilities such as searching Naver News, summarizing results, managing watches/groups, or converting chat requests into monitoring rules. Because the actual behavior is substantially narrower and materially different from the declared purpose, this is a description-behavior mismatch for this code chunk.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The code does match part of the description: it searches Naver News via the Naver Search API, supports exclude-word filtering, and supports filtering by recent N days. However, the declared purpose describes a much broader skill centered on briefing, monitoring, persistent state, grouped queries, and watch-rule management. None of those higher-level or stateful features appear in this code chunk. The actual code is a single API client/helper for fetching and filtering news results, not a full monitoring and management workflow tool. Therefore the description materially overstates the implemented capabilities.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The declared description describes a full-featured Naver News search and monitoring skill. However, the supplied code chunk does not implement any of those capabilities. It only adjusts Python import paths in a pytest conftest file, which is a test-support utility. This is materially different from the declared primary purpose and shows none of the claimed news, API, persistence, or automation behavior.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The README states that the skill's core is connecting '채팅형 한국어 요청' and repeatedly describes operation as '한국어 자연어' requests, which indicates the skill is designed to require Korean input. Under the policy rule, forcing a specific language without explicit user opt-in or a clearly justified regional constraint is a natural-language policy violation.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding

The skill advertises commands that read and write local files and access the network, but it does not declare any explicit tool scope or permission boundaries. This increases the chance that an orchestrator or reviewer will invoke the skill with broader capabilities than intended, reducing least-privilege protections and making misuse or accidental overreach harder to detect.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The description uses broad natural-language triggers like 'use when the user wants' followed by many loosely bounded intents, which can cause the skill to activate in contexts not clearly intended by the user. Over-broad routing is dangerous because this skill includes network access, credential setup guidance, and local persistent state operations, so mistaken invocation could lead to unnecessary data handling or state changes.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The instruction to keep public user-facing documentation 'Korean-first' imposes a language preference as policy text without indicating that users may choose another language. Under the policy criteria, forcing a specific language without user opt-in is a natural-language policy violation unless clearly justified as region-specific.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
86% confidence
Finding

Core parsing logic is built around Korean trigger words, Korean time-of-day phrases, and Korean output text, with no natural-language indication that users may choose another language or locale. This can violate language/locale policy when a skill implicitly forces a specific language without opt-in or documented regional scoping.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The code builds shell commands by interpolating user-derived values such as plan.raw_request, plan.name_hint, and potentially query-derived command fragments into strings that are later presented as shell_* commands and cron lines. Although this file does not execute them directly, it packages them for later execution by operators/automation systems, creating a command-injection path if quoting is broken or downstream components invoke them via a shell.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The template descriptions are defined only in Korean, and the file contains no indication that Korean output is optional, user-selected, or required for a documented region-specific purpose. This can violate language/locale policy because it forces a specific language without opt-in.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

encode_client_secret_for_storage() handles a client secret and explicitly falls back to returning the secret in plain text storage when DPAPI is unavailable. The code contains no user-facing notice, warning comment, or logging that sensitive credentials may be stored unencrypted depending on platform.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The code writes configuration data to disk via save_config() and set_credentials(), including a client secret that may be stored in plain text on non-Windows systems. There is no confirmation prompt, log/print statement, or explanatory comment/docstring warning users that credentials will be persisted locally.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

Nearly all CLI help text, prompts, status messages, and errors are hard-coded in Korean, while the parser description is in English, and there is no opt-in or locale selection mechanism. Under the policy rule, forcing a specific language without user choice is a natural-language policy concern unless the region-specific constraint is explicitly documented and justified.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The setup flow stores Naver API credentials locally via set_credentials() but does not clearly warn the user before writing secrets to disk. In a CLI skill that manages persistent local state, this can lead to inadvertent secret exposure through filesystem access, backups, syncing, or weak host protections, especially on non-Windows systems where the note about DPAPI appears only later in an error/help path.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

This file hard-codes activation/query parsing around Korean phrases such as '브리핑해줘', '알려줘', and similar terms, and later raises a Korean-only error message. Under the policy, forcing a specific language without user opt-in or a documented regional justification is a natural-language policy violation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
94% confidence
Finding

This code raises user-visible ValueError messages in Korean only, with no indication that the skill is intentionally region-specific or that users can choose a locale. That can violate a language/locale policy requiring neutrality or user opt-in for non-default languages.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
79% confidence
Finding

When --output is provided, the command creates parent directories and writes a JSON bundle to disk, but there is no print/log statement or inline warning indicating that a file is being created or overwritten. For code-file warning checks, file writes should have some visible disclosure unless already clearly surfaced to the user.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
77% confidence
Finding

This code file contains multiple natural-language string literals for requests and error/output expectations exclusively in Korean, which suggests the skill behavior and interface may be fixed to a specific language. Under the policy, forcing a specific language without user opt-in can be a locale-policy violation unless the constraint is clearly documented and justified.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
82% confidence
Finding

This code hard-codes Korean output expectations such as '네이버 뉴스 멀티 브리핑' and Korean query/title content, which indicates the skill behavior is tied to a specific language. Under the policy rule, forcing a specific language without opt-in or clear documented regional justification is a natural-language policy concern.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.