Back to skill

Security audit

Auto Estimate Generator

Security checks for vulnerabilities and agentic risk

Overview

This skill is a coherent construction estimating helper, but users should treat generated Excel files and estimate inputs as sensitive business data.

Install only if you are comfortable giving the skill filesystem access for project estimate workflows. Use trusted input files, review unmapped and matched items carefully, save exported workbooks only to appropriate project locations, and be cautious opening generated spreadsheets from untrusted QTO data because formula-like text may be preserved unless the implementation is hardened.

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
SKILL.md:213
Finding

Spreadsheet Formula Injection in Excel Exports

Content
View full analysis
str: """Export estimate to Excel.""" result = self.generate_estimate() with pd.ExcelWriter(output_path, engine='openpyxl') as writer: # Summary summary_df = pd.DataFrame([{ 'Project': self.project_name, 'Total QTO Items': result['total_qto_items'], 'Mapped Items': result['mapped_items'], 'Unmapped Items': result['unmapped_items'], 'Mapping Rate %': result['mapping_rate'], 'Total Cost': result['total_cost'] }]) summary_df.to_excel(writer, sheet_name='Summary', index=False) # Estimate items items_df = pd.DataFrame([{ 'Element ID': item.qto_element_id, 'Description': item.description, 'Quantity': item.quantity, 'Unit': item.unit, 'Unit Cost': item.unit_cost, 'Total Cost': item.total_cost, 'WBS': item.wbs_code, 'Rule': item.rule_applied } for item in self.estimate_items]) items_df.to_excel(writer, sheet_name='Estimate', index=False) # By element type by_type_df = pd.DataFrame([ {'Element Type': k, 'Cost': v} for k, v in self.get_cost_by_element_type().items() ]) by_type_df.to_excel(writer, sheet_name='By Type', index=False) # Unmapped items unmapped_df = self.get_unmapped_summary() if not unmapped_df.empty: unmapped_df.to_excel(writer, sheet_name='Unmapped', index=False) return output_path ``` ### Technical Analysis The export routine writes values derived from user-provided QTO and pricing-rule data directly into an XLSX workbook through Pandas and `openpyxl`. Re ...[truncated 2216 chars]
Remediation
View remediation
pd.DataFrame: return df.map(sanitize_excel_value) items_df = sanitize_dataframe(items_df) items_df.to_excel(writer, sheet_name="Estimate", index=False) ``` Where supported, explicitly forcing untrusted cells to the spreadsheet text type is preferable to relying solely on prefix escaping. ]]>

T09 · Insecure Skill Coding Practices

Note
Location
SKILL.md:129
Finding

Pricing Rules Match When Required Properties Are Missing

Content
View full analysis
Optional[PricingRule]: """Find pricing rule that matches QTO item.""" matching_rules = [] for rule in self.pricing_rules: if rule.element_type != qto_item.element_type: continue # Check conditions match = True for key, value in rule.conditions.items(): if key.endswith('_min'): prop_name = key[:-4] if prop_name in qto_item.properties: if qto_item.properties[prop_name] < value: match = False elif key.endswith('_max'): prop_name = key[:-4] if prop_name in qto_item.properties: if qto_item.properties[prop_name] > value: match = False else: if key in qto_item.properties: if qto_item.properties[key] != value: match = False if match: matching_rules.append(rule) # Return most specific rule (most conditions) if matching_rules: return max(matching_rules, key=lambda r: len(r.conditions)) return None ``` ### Technical Analysis The rule matcher initializes `match` to `True`, but only compares a condition when the corresponding QTO property exists. If a required property is absent, no branch changes `match` to `False`. This behavior applies to exact-match conditions and minimum or maximum conditions. For example, a rule requiring `material = Masonry` can remain eligible for an item with no `material` property. Likewise, a thickness-constrained rule can match an item that contains no thickness value. The implementation therefore treats missing evidence as satisfying a condition. Becaus ...[truncated 1467 chars]
Remediation
View remediation
value: match = False break else: if key not in qto_item.properties: match = False break if qto_item.properties[key] != value: match = False break ``` Numeric conditions should additionally verify that both operands are finite numeric values before comparison. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
Findings (1)

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
90% confidence
Finding

The skill includes functionality to export estimate and QTO-derived data to an Excel file, but the markdown description does not warn users that project data will be written to disk. In a construction estimating context, exported files may contain sensitive commercial, pricing, or project details, so omission of this behavior reduces informed consent and can lead to accidental data exposure on shared systems.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.