Back to skill

Security audit

TXT电子书清洗修复

Security checks for vulnerabilities and agentic risk

Overview

This TXT ebook cleaner needs Review because it can search local files, upload book contents to cloud/public URLs, send text through a broad OpenClaw agent, and persist AI-learned rules without strong consent or scoping.

Install only if you are comfortable with the skill searching for TXT files, uploading ebook contents outside the device, using an OpenClaw LLM subagent, and saving learned cleanup rules that affect future files. Prefer an explicit local file path, fast/local-only processing, disabled auto_learn, and only process documents you have rights to modify.

Vulnerability Patterns
  • 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
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
Findings (6)

T01 · Skill Instruction Hijacking

Error
Location
scripts/utils/llm_client.py:166
Finding
Untrusted ebook content is passed directly to the privileged main agent<![CDATA[ ## Vulnerability Details **File Location**: `scripts/utils/llm_client.py:166-176`; related prompt construction at `scripts/ai_modules/ad_detector.py:259-263`, `scripts/ai_modules/mojibake_fixer.py:341-343,359-361`, and `scripts/ai_modules/chapter_parser.py:116-118,213-215` **Vulnerability Type**: Indirect prompt injection across a privileged agent boundary **Risk Level**: High ### Vulnerable Code ```python # scripts/utils/llm_client.py result = subprocess.run( [ 'openclaw', 'agent', '--local', '--agent', 'main', '--message', prompt, '--json' ], capture_output=True, text=True, timeout=self.timeout + 30 ) ``` Untrusted text is directly interpolated into prompts: ```python # scripts/ai_modules/ad_detector.py para_list = "\n".join([f"[{i}] {p}" for i, p in enumerate(paragraphs)]) prompt = BATCH_AD_DETECTION_PROMPT.format(paragraphs=para_list) response = self.llm.call(prompt) ``` ```python # scripts/ai_modules/mojibake_fixer.py prompt = MOJIBAKE_FIX_PROMPT.format(text=text) response = self.llm.call(prompt) ``` ```python # scripts/ai_modules/chapter_parser.py prompt = CHAPTER_PARSE_PROMPT.format(text_sample=sample) response = self.llm.call(prompt) ``` ### Technical Analysis Ebook content is attacker-controlled data. The Skill inserts that data directly into natural-language prompts and sends the resulting prompts to the OpenClaw `main` agent. The input is not isolated using a separate, tool-free execution context, and there is no prompt-injection detection or enforceable distinction between instructions and document data. The prompts request JSON-only output, but this is a natural-language instruction rather than a security boundary. A malicious TXT document can contain instructions such as requests to ignore the cleanup task, reveal contextual information, or invoke capabilities available to the main agent. JSON parsing after execution does not prevent the agent from following injected ins ...[truncated 1242 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Replace the `main` agent invocation with a dedicated analysis-only model context that has no filesystem, network, messaging, shell, memory, or other tools. 2. Treat all ebook content as untrusted data and place it in an explicit structured field rather than concatenating it into the instruction body. 3. Enforce a strict response schema at the model API boundary, including field types, size limits, index bounds, and allowed enumeration values. 4. Add prompt-injection detection and reject document fragments containing instruction-like attempts to alter the model role or task. 5. Apply deterministic validation before modifying the document. For example, verify that returned source text exists in the submitted fragment and that only approved transformations are made. 6. Document that AI modes transmit content to another model context and require explicit user consent before enabling them. ]]>

T02 · Agent Memory Poisoning

Error
Location
scripts/ai_modules/mojibake_fixer.py:440
Finding
Model-generated mojibake mappings are persisted and applied to future documents<![CDATA[ ## Vulnerability Details **File Location**: `scripts/ai_modules/mojibake_fixer.py:91-103,145-150,440-452,465-472`; enabled by `config/ai_config.yaml:18-24` **Vulnerability Type**: Persistent rule poisoning through untrusted LLM output **Risk Level**: High ### Vulnerable Code ```python # scripts/ai_modules/mojibake_fixer.py self.auto_learn = self.config.get('auto_learn', True) self.learned_rules: Dict[str, str] = {} self._load_learned_rules() ``` ```python # Model-supplied confidence controls persistence if self.auto_learn and ai_result.confidence > 0.9: self._learn_from_fix(ai_result) ``` ```python def _learn_from_fix(self, result: MojibakeFixResult) -> None: """Learn new rules from a repair result.""" for change in result.changes: before = change.get('before', '') after = change.get('after', '') if before and len(before) <= 10: if before not in self.learned_rules: self.learned_rules[before] = after logger.info(f"Learning new rule: '{before}' -> '{after}'") self._save_learned_rules() ``` ```python def _save_learned_rules(self) -> None: rules_file = os.path.join( os.path.dirname(__file__), '..', '..', 'references', 'learned_mojibake_rules.json' ) try: os.makedirs(os.path.dirname(rules_file), exist_ok=True) with open(rules_file, 'w', encoding='utf-8') as f: json.dump(self.learned_rules, f, ensure_ascii=False, indent=2) ``` The persisted rules are later merged into global replacement rules: ```python all_rules = {**mojibake_map, **self.learned_rules} for mojibake, correct in all_rules.items(): if mojibake in fixed_text: fixed_text = fixed_text.replace(mojibake, correct) ``` ### Technical Analysis The learning mechanism trusts the model-provided `changes` array and the model-provided confidence score. It does not verify that: - `before` appeared in the submitted source text; - `after` is a plau ...[truncated 1422 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Disable `auto_learn` by default. 2. Require explicit user or administrator approval before making a learned rule persistent. 3. Do not trust model-reported confidence as authorization to write persistent state. 4. Verify that every `before` value occurs in the exact submitted input and is classified as mojibake by deterministic rules. 5. Restrict both source and replacement values to carefully defined character sets and length limits. 6. Store learned mappings per document or per temporary run instead of globally. 7. Add provenance, review status, creation time, and source hashes to persisted mappings. 8. Use an allowlisted rules file shipped read-only with the Skill for production processing. 9. Provide a safe reset mechanism and integrity checks for the learned-rules file. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/ai_enhanced_cleaner.py:67
Finding
The documented fast mode may continue to invoke AI processing<![CDATA[ ## Vulnerability Details **File Location**: `scripts/ai_enhanced_cleaner.py:67-93,121-135,370-375` **Vulnerability Type**: Security mode applied after dependent modules are initialized **Risk Level**: High ### Vulnerable Code ```python def __init__(self, config_path: Optional[str] = None): self.config = self._load_config(config_path) self.mode = self.config.get('mode', 'balanced') self._apply_mode_config() self.llm_client = init_client(self.config) self.ad_detector = AIAdDetector(self.config, self.llm_client) self.mojibake_fixer = AIMojibakeFixer(self.config, self.llm_client) self.chapter_parser = AIChapterParser(self.config, self.llm_client) ``` The default configuration path is also inconsistent with the supplied project layout: ```python if config_path is None: config_path = os.path.join( os.path.dirname(__file__), 'config', 'ai_config.yaml' ) ``` Because `__file__` is under `scripts/`, this resolves to `scripts/config/ai_config.yaml`, while the supplied configuration is at `config/ai_config.yaml`. The CLI mode is changed after module initialization: ```python cleaner = AIEnhancedTxtCleaner(args.config) if args.mode: cleaner.mode = args.mode cleaner._apply_mode_config() ``` Each module copied its enabled state during construction: ```python # Example from AIAdDetector.__init__ self.enabled = self.config.get('enabled', True) ``` ### Technical Analysis The Skill documentation represents `fast` mode as having all AI features disabled. However, the cleaner is first constructed using the configured or fallback `balanced` mode, and the AI modules copy their enabled settings during that construction. The command-line mode is applied afterward by mutating the shared configuration dictionary. It does not update `self.ad_detector.enabled`, `self.mojibake_fixer.enabled`, or `self.chapter_parser.enabled`. Consequently, selecting `-m fast` does not reliably disable modules that w ...[truncated 1108 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Parse and validate the final CLI mode before constructing `AIEnhancedTxtCleaner` or any AI module. 2. Pass the selected mode into the constructor and apply it before initializing the LLM client and dependent modules. 3. Correct the default path to reference `../config/ai_config.yaml`, preferably using `pathlib.Path`. 4. Fail closed if the expected configuration cannot be loaded instead of silently enabling fallback AI behavior. 5. If runtime mode changes remain supported, update or reconstruct every dependent module. 6. Add tests asserting that fast mode produces zero LLM subprocess calls and does not write learned rules. 7. Ensure the top-level `ai_enhancement.enabled` switch is enforced by every AI module. ]]>

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
SKILL.md:84
Finding
Local documents are unnecessarily uploaded to cloud storage through a URL workflow<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:84-89,176-181,199-202` **Vulnerability Type**: Excessive data access and unnecessary external transfer **Risk Level**: Medium ### Vulnerable Instructions ```text ### Phase One: File Acquisition 1. Use search_file to search for TXT files on the user's phone 2. Use upload_file to upload the file to the cloud and obtain a URL 3. Use curl to download it into the working directory ``` The documented example follows the same path: ```text 1. search_file(query="Three Body txt") -> Found: /storage/.../Three Body.txt 2. upload_file(fileInfos=[{"mediaUri": "file://docs/..."}]) -> Obtain a public URL 3. curl -o "Three Body.txt" "URL" -> Download into the working directory ``` ### Technical Analysis The cleanup scripts accept ordinary local paths and can read files directly. Uploading the selected file to cloud storage and downloading it again is therefore not necessary for the declared cleanup function. The instructions do not identify the cloud provider, retention period, access-control model, deletion process, or whether the resulting URL is private and short-lived. The example explicitly describes obtaining a public URL. This exceeds the minimum data-transfer privileges needed to clean a local TXT file. ### Attack Path 1. A user asks the Skill to clean a local ebook or other TXT document. 2. The Skill searches the user's device and identifies the selected file. 3. Following `SKILL.md`, it uploads the file to cloud storage. 4. A URL is generated and then passed to `curl`. 5. The document now exists outside the user's local trust boundary and may remain available according to unspecified provider behavior. ### Impact Assessment The primary impact is confidentiality loss. Private documents, annotations, personal writing, or copyrighted content can be disclosed to a cloud provider or anyone able to access the generated URL. No evidence establishes that the URL is securely scoped or that u ...[truncated 47 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Read local files directly from their confirmed local paths. 2. Remove `upload_file` and `curl` from the default cleanup workflow. 3. If platform constraints genuinely require upload, obtain explicit informed user consent before transfer. 4. Clearly identify the destination provider, retention policy, access controls, and deletion behavior. 5. Use private, single-use, short-lived URLs rather than public URLs. 6. Delete the uploaded object immediately after processing and verify deletion. 7. Restrict file search to user-approved directories and require confirmation before opening the selected file. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/ai_enhanced_cleaner.py:381
Finding
Report path construction can overwrite the cleaned output file<![CDATA[ ## Vulnerability Details **File Location**: `scripts/ai_enhanced_cleaner.py:381-386`; duplicate pattern at `scripts/clean_txt.py:798-801` **Vulnerability Type**: Unsafe output-path derivation causing destructive overwrite **Risk Level**: Medium ### Vulnerable Code ```python # scripts/ai_enhanced_cleaner.py if args.report: report_md = cleaner.generate_report_markdown(report) report_path = output_path.replace('.txt', '_报告.md') with open(report_path, 'w', encoding='utf-8') as f: f.write(report_md) print(f"Report saved: {report_path}") ``` The legacy cleaner uses the same pattern: ```python report_path = ( output_path.replace('.txt', '_清理报告.md') if output_path else input_path.replace('.txt', '_清理报告.md') ) report = generate_report( input_path, original_len, cleaned_len, stats, output_path or input_path ) with open(report_path, 'w', encoding='utf-8') as f: f.write(report) ``` ### Technical Analysis `str.replace('.txt', suffix)` only changes paths containing the exact lowercase substring `.txt`. If an explicitly supplied output path does not contain that substring—for example, `output.dat`, `output.TXT`, or a path with no extension—`replace()` returns the original path unchanged. The cleaned text is first written to `output_path`. Report generation then opens the same path in write mode and replaces the cleaned content with Markdown. ### Attack Path 1. A user runs the enhanced cleaner with an output such as `-o cleaned.dat --report`. 2. `clean_file()` writes the cleaned ebook to `cleaned.dat`. 3. `cleaned.dat`.replace(`.txt`, `_report.md`) still equals `cleaned.dat`. 4. The report writer opens `cleaned.dat` with mode `w`. 5. The cleaned ebook is truncated and replaced by the Markdown report. ### Impact Assessment The vulnerability causes deterministic data loss in the generated output. It does not grant additional system privileges, but it can destroy the only cleaned copy and mislead the user into believ ...[truncated 90 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Use `pathlib.Path` to derive a separate report filename independently of the original extension. 2. For example, use `output.with_name(output.stem + "_report.md")`. 3. Compare fully resolved output and report paths and abort if they are identical. 4. Support uppercase and non-TXT extensions without relying on string replacement. 5. Write both files atomically through temporary files followed by safe renaming. 6. Add tests for extensionless paths, uppercase extensions, non-TXT extensions, and filenames containing `.txt` outside the suffix. ]]>

T08 · Insecure Dependencies

Note
Location
SKILL.md:76
Finding
Runtime dependencies are installed without version or integrity pinning<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:76-80` **Vulnerability Type**: Unpinned third-party dependency installation **Risk Level**: Low ### Vulnerable Instructions ```text ## Dependencies - Python 3.6+ - chardet library: pip install chardet - PyYAML library: pip install pyyaml (AI-enhanced mode) - requests library: pip install requests (AI-enhanced mode) ``` ### Technical Analysis The Skill instructs users to install mutable latest releases directly from the default package index. It provides no lock file, reviewed version constraints, hashes, or isolated installation procedure. This makes builds non-reproducible and allows future package releases to alter the executable dependency set after the Skill itself has been audited. The inspected executable code does not use `requests`, making that package an unnecessary addition to the dependency and supply-chain surface. This finding does not establish that any named dependency is currently malicious. It identifies an unsafe dependency-management practice. ### Attack Path 1. A user follows the installation instructions. 2. `pip` resolves whatever package versions are current at installation time. 3. A compromised, malicious, or incompatible future release can be downloaded and installed. 4. Package installation or later imports execute with the user's Python environment permissions. 5. The Skill receives the dependency's changed behavior despite no change to the audited project files. ### Impact Assessment A compromised dependency could execute with the same filesystem and network privileges as the Skill process. More commonly, unpinned versions may cause incompatible or inconsistent behavior. The unnecessary `requests` package increases exposure without supporting the inspected runtime implementation. ]]>
Remediation
<![CDATA[ ## Remediation Suggestions 1. Provide a reviewed lock file with exact versions. 2. Pin package versions and hashes, for example by using `pip install --require-hashes -r requirements.txt`. 3. Install dependencies in an isolated virtual environment. 4. Remove `requests` unless executable code genuinely requires it. 5. Define and test a supported Python version range rather than relying on an outdated broad minimum. 6. Add automated dependency vulnerability scanning and controlled update review. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (43)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
This finding is especially concerning because it describes a generic prompt-execution path via a local/external agent (`openclaw agent`) and subprocess invocation, which is far broader than ebook cleanup. That means the skill may act as a general agent wrapper with shell-mediated execution and external interaction, materially increasing risk of command abuse, unintended data exposure, and capability escalation beyond the declared purpose.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
This finding is especially concerning because it describes a generic prompt-execution path via a local/external agent (`openclaw agent`) and subprocess invocation, which is far broader than ebook cleanup. That means the skill may act as a general agent wrapper with shell-mediated execution and external interaction, materially increasing risk of command abuse, unintended data exposure, and capability escalation beyond the declared purpose.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
This finding is especially concerning because it describes a generic prompt-execution path via a local/external agent (`openclaw agent`) and subprocess invocation, which is far broader than ebook cleanup. That means the skill may act as a general agent wrapper with shell-mediated execution and external interaction, materially increasing risk of command abuse, unintended data exposure, and capability escalation beyond the declared purpose.

Missing User Warnings

High
Confidence
97% confidence
Finding
The workflow explicitly says files are uploaded to the cloud and processed with AI-enhanced components, but the description does not clearly warn users that ebook contents may leave the device and be sent to external services. This is a significant privacy and consent issue, especially for potentially copyrighted, personal, or sensitive text files, and the risk is amplified by the hidden LLM/agent behavior suggested by other findings.

Context-Inappropriate Capability

High
Confidence
94% confidence
Finding
This module launches an external CLI agent to process arbitrary prompts, giving the skill a broad execution and delegation capability that is not justified by the advertised TXT-cleaning purpose. In the context of a narrowly scoped ebook repair skill, spawning a general-purpose local agent expands the attack surface, may expose local data to another toolchain, and can enable unintended capabilities beyond simple text cleanup.

Context-Inappropriate Capability

Medium
Confidence
92% confidence
Finding
The design adds external LLM/API processing to a skill whose primary purpose is local TXT cleanup, creating a new data-exfiltration path for user-supplied book content. Because the document explicitly configures third-party providers and sends paragraphs, corrupted text, and chapter samples for analysis without strong scope limitation or privacy controls, sensitive or copyrighted content could be transmitted off-device unexpectedly.

Missing User Warnings

Medium
Confidence
97% confidence
Finding
The design describes sending text to external LLM APIs for ad detection, mojibake repair, and chapter analysis, but it does not provide a clear user warning or informed-consent step. In this skill context, users reasonably expect local text cleaning; omitting disclosure increases the risk of silent transmission of private, sensitive, or copyrighted material to third-party services.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
This markdown file documents AI-enhanced behavior including LLM-based text analysis and 'high-confidence repairs automatically saved as new rules,' but it does not include any warning about potential privacy implications of sending text to an LLM or about persistent modification of rule data. Under the markdown-file criteria, behaviors that could affect user data or privacy should be disclosed to users.

Lp3

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding
The skill describes capabilities that require file access, shell execution, and network transfer, but it does not declare any explicit tool scope or permission boundaries. This creates a hidden-capability problem: reviewers and users cannot easily see what the skill is allowed to do, increasing the chance of over-privileged execution or unsafe invocation paths.

Vague Triggers

Medium
Confidence
91% confidence
Finding
The trigger phrases are broad enough to match ordinary requests about cleaning or fixing text files, which can cause the skill to activate unexpectedly in contexts the user did not intend. Over-broad triggering becomes more dangerous here because the skill also appears to use file access, uploads, shell steps, and AI processing, so accidental activation can expose local content or initiate external processing without clear user intent.

Natural-Language Policy Violations

Medium
Confidence
82% confidence
Finding
This manifest/config file contains user-facing natural-language comments entirely in Chinese, including operational descriptions such as processing modes and feature explanations. Under the policy, forcing a specific language without opt-in or justification is a natural-language locale violation, and no alternative language or opt-in mechanism is documented here.

Description-Behavior Mismatch

Medium
Confidence
91% confidence
Finding
The skill is described as a local TXT cleaning/repair tool, but this configuration enables AI enhancement through an LLM subagent provider. That creates a capability mismatch: user book content may be transmitted to another model-backed component, introducing confidentiality and trust-boundary risks that are not obvious from the stated purpose.

Context-Inappropriate Capability

Medium
Confidence
84% confidence
Finding
Using an external/provider-backed LLM is not clearly necessary for the advertised TXT repair function, especially when handling potentially copyrighted or sensitive ebook text. If paragraphs are sent to a provider or subagent, users may unknowingly expose local file contents, and the added dependency expands the attack surface beyond simple text cleanup.

Vague Triggers

Medium
Confidence
91% confidence
Finding
The trigger phrases are broad enough to match common requests like '去广告' or '修乱码' without requiring clear TXT/ebook context, which can cause the skill to activate outside its intended scope. In an agent environment, overbroad activation can lead to unintended file discovery or processing on the user's device, especially because the skill supports local file search workflows.

Vague Triggers

Medium
Confidence
94% confidence
Finding
The skill permits ambiguous fuzzy requests like '清理一本txt' and instructs the agent to search the user's device for candidate files. This expands the skill from acting on a user-specified file to proactively enumerating local files, which increases privacy risk and creates opportunities for unintended activation from vague user language.

Description-Behavior Mismatch

Medium
Confidence
94% confidence
Finding
The script initializes an LLM client and routes book content through AI modules for ad detection, mojibake fixing, and chapter parsing. That means user-provided text may be transmitted to an external model provider, which is a meaningful data exposure/security behavior not obvious from a simple 'txt cleaner/repair' description.

Missing User Warnings

Medium
Confidence
97% confidence
Finding
The cleaning pipeline sends the full text through LLM-backed modules without any clear user-facing warning, consent gate, or privacy notice. Because ebooks and txt files may contain personal notes, proprietary material, or sensitive text, silent network transmission to a third-party provider creates a real confidentiality risk.

Natural-Language Policy Violations

Medium
Confidence
90% confidence
Finding
The `_normalize_punctuation` logic automatically converts ASCII punctuation to Chinese punctuation based on Chinese-character context, which imposes a specific locale convention on processed text. The file does not provide any user opt-in, toggle, or documented justification for this language-specific transformation.

Description-Behavior Mismatch

Medium
Confidence
96% confidence
Finding
The detector sends user book paragraphs to an external LLM service for ad classification, which introduces data exfiltration beyond simple local text cleanup. In this skill context, users are likely supplying full pirated or personal ebook content, so transmitting raw paragraphs off-device creates a real privacy and scope-expansion risk even if the feature is intended for functionality.

Ssd 1

Medium
Confidence
92% confidence
Finding
The batch prompt combines multiple untrusted paragraphs in one context, allowing one malicious sample to influence classification of other samples or the format of the whole response. In this skill, the input text is precisely the kind of messy, externally sourced content that may contain adversarial strings, making cross-item prompt contamination more likely.

Context-Inappropriate Capability

Medium
Confidence
91% confidence
Finding
The batch detection path performs network-backed LLM analysis on paragraph content without this being clearly necessary from the declared skill scope of text cleaning and repair. Because the skill processes ebook text at scale, this can expose substantial user-provided content to a third party and broadens the trust boundary.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
This code sends paragraph content to an LLM but contains no visible user-facing warning, consent check, or policy gate near the transmission point. In a text-repair skill, silent remote submission is dangerous because users may reasonably expect local processing of their ebooks and not third-party inspection.

Context-Inappropriate Capability

Medium
Confidence
89% confidence
Finding
Single-paragraph detection also transmits raw paragraph text to the LLM, creating the same external data exposure risk as the batch path. Even though only one paragraph is sent at a time, sensitive or copyrighted text can still be disclosed without clear necessity or user awareness.

Ssd 1

Medium
Confidence
90% confidence
Finding
User-controlled paragraph text is inserted directly into the prompt, so a crafted paragraph can contain instruction-like content that attempts to override the ad-classification task or distort the JSON output. This is a real prompt-injection risk because the code trusts a general-purpose LLM to follow the surrounding instructions while processing adversarial text.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The single-paragraph LLM call has the same undisclosed transmission issue and can leak text content outside the local environment. Lack of transparency increases privacy and compliance risk, especially where uploaded books may contain personal annotations or copyrighted material.

Static analysis

No suspicious patterns detected.