Back to skill

Security audit

huawei-cloud-kafka-replica-reassignment

Security checks for vulnerabilities and agentic risk

Overview

The skill is coherent for Kafka reassignment planning, but its web UI exposes shared uploads and generated Kafka artifacts over an unauthenticated all-interfaces server and has unescaped HTML output risks.

Install only if you understand the web UI exposure. Prefer the CLI path or change the UI to bind to 127.0.0.1, add authentication if remotely reachable, isolate jobs per user, escape all displayed spreadsheet and filename values, and pin dependencies before using real Kafka topology or capacity data.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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
Findings (2)

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/app.py:325
Finding

Unauthenticated Network Access to Shared Uploads, Pipeline State, and Kafka Artifacts

Content
View full analysis

Vulnerability Details

File Location: scripts/app.py:53-76, 125-131, 325-482, 508
Vulnerability Type: Missing authentication and tenant isolation in a network-accessible service
Risk Level: High

Code Snippet

python
WORK_DIR = os.environ.get('KAFKA_REASSIGN_WORK_DIR') or os.path.join(
    tempfile.gettempdir(), 'kafka-replica-reassignment-work')
UPLOAD_DIR = os.path.join(WORK_DIR, 'uploads')
OUTPUT_DIR = os.path.join(WORK_DIR, 'output')

pipeline_state = {
    'status': 'idle',
    ...
}
python
# Clear the output directory.
out_abs = os.path.abspath(OUTPUT_DIR)
if out_abs.startswith(os.path.abspath(WORK_DIR) + os.sep) and os.path.exists(out_abs):
    shutil.rmtree(out_abs)
os.makedirs(out_abs, exist_ok=True)
python
@app.route('/api/upload', methods=['POST'])
def upload_files():
    topic_file = request.files.get('topic')
    broker_file = request.files.get('broker')

    ...

    if topic_file:
        topic_path = os.path.join(UPLOAD_DIR, 'topic.xlsx')
        topic_file.save(topic_path)

    if broker_file:
        broker_path = os.path.join(UPLOAD_DIR, 'broker.xlsx')
        broker_file.save(broker_path)
python
@app.route('/api/run', methods=['POST'])
def run_pipeline():
    topic_path = os.path.join(UPLOAD_DIR, 'topic.xlsx')
    broker_path = os.path.join(UPLOAD_DIR, 'broker.xlsx')

    ...

    thread = threading.Thread(
        target=run_pipeline_thread,
        args=(topic_path, broker_path, params)
    )
    thread.daemon = True
    thread.start()

    return jsonify({'status': 'started', 'message': 'Pipeline started'})
python
@app.route('/api/status')
def get_status():
    return jsonify({
        'status': pipeline_state['status'],
        'stages': pipeline_state['stages'],
        'params': pipeline_state['params'],
        'log': pipeline_state['log'][-50:],
        'report_available': pipeline_state['report_path'] is not None,
        ...
    })


@app.route('/api/report')
def get_report():
 
...[truncated 3765 chars]
Remediation
View remediation

Remediation Suggestions

  1. Bind to loopback by default:

    python
    host = os.environ.get('HOST', '127.0.0.1')
    app.run(host=host, port=port, debug=False)
    
  2. If remote access is required, place the service behind authenticated TLS and enforce authentication and authorization in the application or trusted reverse proxy.

  3. Introduce per-user and per-job isolation:

    • Generate a cryptographically random job ID.
    • Store uploads and outputs under a dedicated job directory.
    • Associate each job with the authenticated owner.
    • Check ownership on upload, run, status, report, listing, and download routes.
    • Do not expose predictable global artifact paths.
  4. Replace the process-global state dictionary with synchronized, job-scoped state. Use locks or an appropriate task queue to prevent upload/run races.

  5. Require explicit confirmation before deleting or replacing existing job artifacts, consistent with the project's execution-safety instructions.

  6. Add CSRF protection to state-changing browser routes and reject cross-origin requests with an explicit origin policy.

  7. Apply upload size limits, request rate limits, job quotas, and processing timeouts to reduce denial-of-service exposure.

  8. Use a production WSGI server rather than Flask's development server for any non-local deployment.

T09 · Insecure Skill Coding Practices

Warning
Location
templates/index.html:451
Finding

Stored HTML and JavaScript Injection Through Uploaded Filenames and Spreadsheet Values

Content
View full analysis

Vulnerability Details

File Location: templates/index.html:451-492; related sources in scripts/app.py:340-356, 444-455 and scripts/report.py:17-48, 59-84, 210-219
Vulnerability Type: Stored cross-site scripting caused by unescaped untrusted content
Risk Level: Medium

Code Snippet

The upload route records the client-supplied original filename in a shared log:

python
if topic_file:
    topic_path = os.path.join(UPLOAD_DIR, 'topic.xlsx')
    topic_file.save(topic_path)
    uploaded['topic'] = topic_file.filename
    pipeline_state['uploads']['topic_uploaded'] = True
    pipeline_state['uploads']['topic_filename'] = topic_file.filename
    log(f'Topic file uploaded: {topic_file.filename}')

if broker_file:
    broker_path = os.path.join(UPLOAD_DIR, 'broker.xlsx')
    broker_file.save(broker_path)
    uploaded['broker'] = broker_file.filename
    pipeline_state['uploads']['broker_uploaded'] = True
    pipeline_state['uploads']['broker_filename'] = broker_file.filename
    log(f'Broker file uploaded: {broker_file.filename}')

The status route returns those log entries and validation details:

python
@app.route('/api/status')
def get_status():
    return jsonify({
        'status': pipeline_state['status'],
        'stages': pipeline_state['stages'],
        'params': pipeline_state['params'],
        'log': pipeline_state['log'][-50:],
        ...
    })

The browser inserts returned strings into HTML without escaping:

javascript
if (s.result.reason || s.result.message) {
    detailHtml += `<br><span class="check-fail">[${s.result.reason || ''}]</span> ${(s.result.message || '').substring(0, 200)}`;
}

if (stage === 'stage3' && Array.isArray(s.result.validation_details)) {
    const fails = s.result.validation_details.filter(c => c.status === 'FAIL');
    if (fails.length) {
        detailHtml += `<br><span class="check-fail">失败校验项:</span><br>`;
        detailHtml += fails.slice(0, 5).map(
            c => `&nbsp;&nbsp;<spa
...[truncated 4368 chars]
Remediation
View remediation

Remediation Suggestions

  1. Stop inserting untrusted values through innerHTML. Build elements with document.createElement() and assign untrusted values through textContent.

    Example:

    javascript
    logArea.replaceChildren();
    for (const entry of data.log) {
        const line = document.createElement('div');
        line.className = 'log-line';
        line.textContent = entry;
        logArea.appendChild(line);
    }
    
  2. Apply the same pattern to validation details, summaries, result messages, and output filenames. Keep static formatting in pre-created DOM elements rather than interpolated HTML strings.

  3. Escape every dynamic report value using html.escape(value, quote=True) before including it in HTML:

    python
    from html import escape
    
    safe_mount = escape(str(row[4]), quote=True)
    safe_usage = escape(str(usage), quote=True)
    
  4. Use a template engine with automatic HTML escaping for the report rather than manually concatenating HTML.

  5. Treat original upload filenames as display-only metadata:

    • Normalize or replace them with generated identifiers.
    • Never place them in HTML without escaping.
    • Avoid including raw filenames in shared logs.
  6. Add a restrictive Content Security Policy that disallows inline scripts and event handlers. This is defense in depth and does not replace output encoding.

  7. Add regression tests covering malicious markup in multipart filenames, broker mount paths, validation messages, report fields, and output file listings.

Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Memory PoisoningPersistent Context Injection, Context Window Stuffing, Memory Manipulation
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (25)

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 164)May include surrounding context.

md
- **Template download**: download blank templates (`topic_template.xlsx`, `broker_template.xlsx`)

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 164)May include surrounding context.

md
- **Template download**: download blank templates (`topic_template.xlsx`, `broker_template.xlsx`)

Memory Manipulation

High
Category
Memory Poisoning
Confidence
80% confidence
Finding

Skill manipulates agent memory, state, or stored context. Memory corruption can alter personality, override safety rules, or cause unpredictable behavior.

Content

Scanner excerpt · scripts/tabio.py (reported line 109)May include surrounding context.

python
def artifact_path(output_dir, name, legacy_name=None):
    """Locate an artifact: prefer the new name; fall back to the legacy file if
    the new name is missing but the legacy one exists."""
    path = os.path.join(output_dir, name)
    if legacy_name and not os.path.exists(path):
        legacy = os.path.join(output_dir, legacy_name)

Hidden Instructions

High
Category
Prompt Injection
Confidence
70% confidence
Finding

Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Content

Scanner excerpt · templates/index.html (reported line 84)May include surrounding context.

html
</div>

    <div class="container">
        <!-- Status Banner -->
        <div id="statusBanner" class="status-banner idle">
            状态:待机 — 上传文件并配置参数后点击"开始执行"
        </div>

Hidden Instructions

High
Category
Prompt Injection
Confidence
70% confidence
Finding

Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Content

Scanner excerpt · templates/index.html (reported line 84)May include surrounding context.

html
</div>

    <div class="container">
        <!-- Status Banner -->
        <div id="statusBanner" class="status-banner idle">
            状态:待机 — 上传文件并配置参数后点击"开始执行"
        </div>

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding

The skill describes capabilities that involve environment variables, filesystem reads/writes, and shell execution, but it does not declare any tool scope or permission boundary in the skill metadata. In an agent setting, this weakens least-privilege controls and can allow broader-than-expected execution against user files or the host environment, especially because the workflow accepts untrusted uploads and invokes scripts/CLI commands.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The file explicitly says the stage report format is emitted in 'the runtime language' and that this version keeps Chinese runtime labels. This imposes a specific language/locale choice in the skill's behavior without documenting user opt-in or an alternative, which matches the locale policy violation criteria.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · evals/run_evals.py (reported line 68)May include surrounding context.

python
def run_stage(script, args):
    proc = subprocess.run([PY, os.path.join(SCRIPTS, script)] + args,
                          cwd=SCRIPTS, capture_output=True, text=True,
                          encoding='utf-8', errors='replace')
    try:

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The file sets the stage name to Chinese and throughout the script emits user-facing CLI help, status messages, blocker explanations, validation summaries, and reports in Chinese only. For a general-purpose automation script, this is a natural-language locale constraint without any opt-in or documented justification, which matches the policy-violation category for forced language/locale.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

This Python file contains multiple hard-coded user-facing strings in Chinese, including error messages, validation output, and command-line help text. Because the skill does not offer any language selection or document a justified locale restriction, it violates the natural-language policy rule on forcing a specific language without user opt-in.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

This code emits user-facing validation messages in Chinese string literals, and later formatting functions continue that pattern for summaries and conclusions. Because the file provides no opt-in, locale selection, or justification that the skill is China-specific, it violates the language/locale policy for natural-language content.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The display formatter produces user-visible headings, counts, and final conclusions in Chinese by default. This forces a specific language on all users and there is no visible mechanism here for language selection or any documented regional limitation.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

This HTML file provides controls to upload local Excel files, execute a multi-stage processing pipeline, and generate downloadable output files, but it does not include any visible warning or disclosure about how uploaded data will be processed, stored, or whether outputs may overwrite or alter server-side files. Under SQP-2 for markdown/code-like files, user-impacting file operations should have some form of user-facing disclosure when they affect user data or system integrity.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
79% confidence
Finding

The docstring states that artifacts are always written to temp directories and that the package stays read-only, then explicitly says '"read-only" is part of the tool's promise'. In this file, the script does perform filesystem writes and deletions via tempfile.mkdtemp and shutil.rmtree; while this is reasonable for an eval harness, it contradicts a literal read-only interpretation in the documentation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
92% confidence
Finding

This Python file contains many user-visible status labels and messages in Chinese, beginning with the test-case name and heading at L134-L135. Under the policy, forcing a specific language without user opt-in is a natural-language policy violation unless the locale restriction is clearly justified.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
92% confidence
Finding

This code emits multiple hard-coded Chinese status and validation messages during pipeline execution, while other UI text in the file is English. That creates a language/locale policy concern because the skill does not offer user opt-in or configuration for the language used in operational output.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
94% confidence
Finding

The module docstring says the broker template keeps Chinese-language headers because the tool's runtime language is Chinese. This imposes a language choice in natural-language documentation without indicating user choice or an explicit region-specific justification, which matches the locale-policy violation criteria.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
91% confidence
Finding

The file contains user-facing labels in Chinese for report sections and statuses, indicating the skill forces a specific language in generated output. The provided code does not offer any opt-in, configuration, or justification for this locale restriction.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
95% confidence
Finding

The dependency is specified as Flask>=2.3.0, which permits installation of any newer version and prevents reproducible builds. This makes it difficult to verify whether a deployed environment includes a vulnerable or breaking release, increasing supply-chain and maintenance risk.

Content

Scanner excerpt · scripts/requirements.txt (reported line 1)May include surrounding context.

text
Flask>=2.3.0
openpyxl>=3.1.0

Unverifiable Dependency: Flask has 10 known advisory(ies) (CVE-2025-47278 (Flask uses fallback key instead of current signing key); CVE-2018-1000656 (Flask is vulnerable to Denial of Service via incorrect encoding of JSON data); CVE-2019-1010083 (Pallets Project Flask is vulnerable to Denial of Service via Unexpected memory u) +7 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
40% confidence
Finding

Dependency has known vulnerabilities (CVEs). Using packages with unpatched security flaws exposes the environment to known exploits.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
95% confidence
Finding

The dependency is specified as openpyxl>=3.1.0, which allows uncontrolled upgrades to later versions. This weakens reproducibility and makes it hard to determine whether the installed package is affected by future or existing supply-chain or security issues.

Content

Scanner excerpt · scripts/requirements.txt (reported line 2)May include surrounding context.

text
Flask>=2.3.0
openpyxl>=3.1.0

Unverifiable Dependency: openpyxl has 2 known advisory(ies) (CVE-2017-5992 (Improper Restriction of XML External Entity Reference in Openpyxl); CVE-2017-5992 (Openpyxl 2.4.1 resolves external entities by default, which allows remote attack)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
40% confidence
Finding

Dependency has known vulnerabilities (CVEs). Using packages with unpatched security flaws exposes the environment to known exploits.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

This code emits a user-facing error string in Chinese (缺 Allocation) and elsewhere defines CLI/help and validation output in Chinese, which effectively forces a specific language for users. The file does not offer localization, a language selection mechanism, or a documented justification for restricting output to Chinese.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
97% confidence
Finding

The argparse description/help text and validation messages are presented in Chinese only, which is a natural-language policy issue when no language preference or locale opt-in is provided. Because these are user-facing strings, they can exclude users who do not read that language.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
94% confidence
Finding

The HTML declares lang="zh-CN" and all visible interface text is in Chinese, which imposes a specific language/locale on users. SQP-3 requires flagging language or locale policy violations when a skill forces a locale without user opt-in or a clearly documented regional justification.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.