Back to skill

Security audit

优惠适用条件核对

Security checks for vulnerabilities and agentic risk

Overview

This skill performs local discount calculations without accessing accounts or placing orders, but users must confirm whether discounts may be combined.

Use merchant-confirmed rules and verify permission to combine discounts before relying on a draft: supplying their order alone enables combined calculations. For reproducible installation, use a reviewed installer version and repository revision.

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
  • 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
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (15)

Description-Behavior Mismatch

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

所提供代码的直接行为是添加外部技能,与声明的订单优惠核验功能存在实质差异。虽然目标技能名称与声明主题相关,但名称不能证明其实际实现了该功能。此判断仅针对所提供的命令,不推断外部技能的内容或安全性。

Content

No source excerpt is available for this finding.

MCP server referenced without pinned version: 'npx skills'.

Medium
Category
MCP Rug Pull
Confidence
90% confidence
Finding

The documented npx skills add command can download and execute an unpinned version of the skills package, exposing users to malicious or compromised future releases with their local permissions. This is a supply-chain risk rather than evidence of an MCP server or malicious author intent; the otherwise limited promotion-calculation functionality does not require or mitigate that installation-time exposure.

Content

No source excerpt is available for this finding.

MCP server referenced without pinned version: 'npx skills'.

Medium
Category
MCP Rug Pull
Confidence
90% confidence
Finding

The installation command invokes npx skills without a pinned version, potentially downloading and executing a changing npm package with the invoking user's permissions. A compromised or malicious future release could therefore execute code during installation; the referenced skill repository is also not pinned to an immutable revision. This is a supply-chain reproducibility risk rather than evidence of an MCP server or malicious intent, and the skill's otherwise bounded discount-calculation purpose does not remove it.

Content

No source excerpt is available for this finding.

Skill declares no tool scope ('permissions' or 'allowed-tools') but code capabilities were detected: file_read, shell.

Medium
Category
MCP Least Privilege
Confidence
70% confidence
Finding

Without declared permissions the skill's intent is opaque and cannot be validated.

Content

No source excerpt is available for this finding.

MCP server referenced without pinned version: 'nPXT'.

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding

npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Content

No source excerpt is available for this finding.

The code treats a supplied stacking order as authorization to combine promotions, despite the manifest requiring missing stacking authorization to remain pending.

Medium
Category
Excessive Agency
Confidence
98% confidence
Finding

The implementation validates stacking_order only as a complete ordering of promotion names, then treats that as sufficient to apply multiple promotions without separately checking merchant authorization to combine them. A supplied order can therefore produce an apparently confirmed payable draft for an unauthorized combination, contrary to the skill's requirement that missing stacking authorization remain pending. This matters for customer-service and operational decisions, although the script's local, advisory-only behavior limits direct financial impact.

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 · scripts/self_test.py (reported line 8)May include surrounding context.

python
checker = root / "scripts/check_eligibility.py"
for filename, expected in [("success.json", "122.00"), ("failure.json", "待确认")]:
    raw = (root / "fixtures" / filename).read_text()
    result = subprocess.run([sys.executable, str(checker)], input=raw, text=True, capture_output=True)
    if result.returncode: raise SystemExit(result.stderr)
    got = json.loads(result.stdout)["calculation"]["应付草稿"]
    if got != expected: raise SystemExit(f"{filename}: got {got}, expected {expected}")

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 · scripts/self_test.py (reported line 49)May include surrounding context.

python
r = subprocess.run([sys.executable, str(checker)], input=json.dumps(data), text=True, capture_output=True)
    return r
def evaluate_raw(raw):
    return subprocess.run([sys.executable, str(checker)], input=raw, text=True, capture_output=True)
partial = json.loads(json.dumps(failure))
partial["promotions"][0].update({"name":"门槛不足但时间未知","eligible_skus":["A"],"threshold_basis":"优惠前商品额","threshold":"200","threshold_includes_shipping":False,"timezone":"Asia/Shanghai"})
partial["promotions"][1].update({"name":"另一优惠","eligible_skus":["A"],"threshold_basis":"商品额","threshold":"0","threshold_includes_shipping":False,"timezone":"No/Such_Zone","start":"2026-01-01T00:00:00+08:00","end":"2027-01-01T00:00:00+08:00"})

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 · scripts/self_test.py (reported line 18)May include surrounding context.

python
# Regression checks: order must override array order, excluded SKU must remain
# undiscounted, and a known type without its value must yield a draft.
success = json.loads((root / "fixtures/success.json").read_text())
result = subprocess.run([sys.executable, str(checker)], input=json.dumps(success), text=True, capture_output=True)
payload = json.loads(result.stdout)
if [step["优惠"] for step in payload["calculation"]["steps"]] != success["stacking_order"]:
    raise SystemExit("stacking_order was not applied")

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 · scripts/self_test.py (reported line 28)May include surrounding context.

python
# without the excluded line this is the documented 100 -> 80 -> 72 case.
order_case = json.loads(json.dumps(success))
order_case["cart"] = [{"sku": "A", "unit_price": "100", "quantity": 1}]
result = subprocess.run([sys.executable, str(checker)], input=json.dumps(order_case), text=True, capture_output=True)
if json.loads(result.stdout)["calculation"]["应付草稿"] != "72.00":
    raise SystemExit("explicit stacking order did not override JSON array order")
order_case["stacking_order"] = ["A款9折", "满100减20"]

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 · scripts/self_test.py (reported line 32)May include surrounding context.

python
if json.loads(result.stdout)["calculation"]["应付草稿"] != "72.00":
    raise SystemExit("explicit stacking order did not override JSON array order")
order_case["stacking_order"] = ["A款9折", "满100减20"]
result = subprocess.run([sys.executable, str(checker)], input=json.dumps(order_case), text=True, capture_output=True)
if json.loads(result.stdout)["calculation"]["应付草稿"] != "70.00":
    raise SystemExit("percent-then-fixed stacking calculation is incorrect")
failure = json.loads((root / "fixtures/failure.json").read_text())

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 · scripts/self_test.py (reported line 36)May include surrounding context.

python
if json.loads(result.stdout)["calculation"]["应付草稿"] != "70.00":
    raise SystemExit("percent-then-fixed stacking calculation is incorrect")
failure = json.loads((root / "fixtures/failure.json").read_text())
result = subprocess.run([sys.executable, str(checker)], input=json.dumps(failure), text=True, capture_output=True)
if "满减金额未提供" not in result.stdout or "折扣比例未提供" not in result.stdout:
    raise SystemExit("missing promotion values were not reported")
failure_output = json.loads(result.stdout)

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 · scripts/self_test.py (reported line 46)May include surrounding context.

python
if later_basis["当前优惠前余额"] != "待确认" or "100.00" in later_basis["公式"]:
    raise SystemExit("a prior pending same-SKU offer must not publish the original cart balance as the later current balance")
def evaluate(data):
    r = subprocess.run([sys.executable, str(checker)], input=json.dumps(data), text=True, capture_output=True)
    return r
def evaluate_raw(raw):
    return subprocess.run([sys.executable, str(checker)], input=raw, text=True, capture_output=True)

Scope Creep

Low
Category
Excessive Agency
Confidence
70% confidence
Finding

Skill's behavior or capabilities extend beyond its stated purpose. Scope creep allows an agent to perform actions unrelated to its documented functionality, increasing the attack surface.

Content

Scanner excerpt · LICENSE (reported line 12)May include surrounding context.

text
permit persons to whom the Software is furnished to do so.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE

Scope Creep

Low
Category
Excessive Agency
Confidence
70% confidence
Finding

Skill's behavior or capabilities extend beyond its stated purpose. Scope creep allows an agent to perform actions unrelated to its documented functionality, increasing the attack surface.

Content

Scanner excerpt · scripts/self_test.py (reported line 262)May include surrounding context.

python
if (superset_clear_result["calculation"]["应付草稿"] != "0.00"
        or any(c["优惠"] == "AB减20" and c["条件"] == "优惠分摊" for c in superset_clear_result["conditions"])):
    raise SystemExit("a later superset offer that certainly consumes the full cart balance must clear the earlier allocation dependency")
# The clearing proof is not limited to a zero threshold: a threshold based on
# the confirmed pre-discount scope total is equally independent of the earlier
# AB line allocation.
superset_positive_threshold = json.loads(json.dumps(superset_clear))

Static analysis

No suspicious patterns detected.