Description-Behavior Mismatch
- Category
- MCP Tool Poisoning
- Confidence
- 98% confidence
- Finding
所提供代码的直接行为是添加外部技能,与声明的订单优惠核验功能存在实质差异。虽然目标技能名称与声明主题相关,但名称不能证明其实际实现了该功能。此判断仅针对所提供的命令,不推断外部技能的内容或安全性。
- Content
Security audit
Security checks for vulnerabilities and agentic risk
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.
所提供代码的直接行为是添加外部技能,与声明的订单优惠核验功能存在实质差异。虽然目标技能名称与声明主题相关,但名称不能证明其实际实现了该功能。此判断仅针对所提供的命令,不推断外部技能的内容或安全性。
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.
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.
Without declared permissions the skill's intent is opaque and cannot be validated.
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.
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.
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
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 calls execute external commands. Without careful input validation, this enables command injection.
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 calls execute external commands. Without careful input validation, this enables command injection.
# 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 calls execute external commands. Without careful input validation, this enables command injection.
# 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 calls execute external commands. Without careful input validation, this enables command injection.
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 calls execute external commands. Without careful input validation, this enables command injection.
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 calls execute external commands. Without careful input validation, this enables command injection.
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)
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.
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
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.
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))
No suspicious patterns detected.