aws-security-mcp 0.6.3 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -19,6 +19,7 @@ interface Finding {
19
19
  module?: string;
20
20
  accountId?: string;
21
21
  accountAlias?: string;
22
+ source?: string;
22
23
  }
23
24
  interface ScanResult {
24
25
  module: string;
package/dist/src/index.js CHANGED
@@ -4,7 +4,7 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
4
4
  import { z } from "zod";
5
5
 
6
6
  // src/version.ts
7
- var VERSION = "0.6.3";
7
+ var VERSION = "0.7.1";
8
8
 
9
9
  // src/utils/aws-client.ts
10
10
  import { STSClient, GetCallerIdentityCommand } from "@aws-sdk/client-sts";
@@ -1017,7 +1017,7 @@ async function dnsResolves(hostname) {
1017
1017
  var DnsDanglingScanner = class {
1018
1018
  moduleName = "dns_dangling";
1019
1019
  async scan(ctx) {
1020
- const { region, partition, accountId } = ctx;
1020
+ const { region, partition } = ctx;
1021
1021
  const startMs = Date.now();
1022
1022
  const findings = [];
1023
1023
  const warnings = [];
@@ -2639,6 +2639,22 @@ import {
2639
2639
  SecurityHubClient as SecurityHubClient2,
2640
2640
  GetFindingsCommand
2641
2641
  } from "@aws-sdk/client-securityhub";
2642
+
2643
+ // src/utils/sh-source.ts
2644
+ function getSecurityHubSource(finding) {
2645
+ const impact = finding.impact ?? "";
2646
+ const match = impact.match(/^Source:\s*([^(]+)/);
2647
+ if (!match) return "Other";
2648
+ const product = match[1].trim();
2649
+ if (product === "Security Hub" || product.includes("Foundational")) return "FSBP";
2650
+ if (product === "Inspector" || product.includes("Inspector")) return "Inspector";
2651
+ if (product === "GuardDuty" || product.includes("GuardDuty")) return "GuardDuty";
2652
+ if (product === "Config" || product.includes("Config")) return "Config";
2653
+ if (product === "IAM Access Analyzer" || product.includes("Access Analyzer")) return "Access Analyzer";
2654
+ return "Other";
2655
+ }
2656
+
2657
+ // src/scanners/security-hub-findings.ts
2642
2658
  function shSeverityToScore(label) {
2643
2659
  switch (label) {
2644
2660
  case "CRITICAL":
@@ -2708,7 +2724,7 @@ var SecurityHubFindingsScanner = class {
2708
2724
  if (recText && !["See References", "None Provided", ""].includes(recText.trim())) {
2709
2725
  remediationSteps.push(recText);
2710
2726
  }
2711
- findings.push({
2727
+ const finding = {
2712
2728
  severity,
2713
2729
  title: f.Title ?? "Security Hub Finding",
2714
2730
  resourceType,
@@ -2722,7 +2738,9 @@ var SecurityHubFindingsScanner = class {
2722
2738
  priority: priorityFromSeverity(severity),
2723
2739
  module: this.moduleName,
2724
2740
  accountId: f.AwsAccountId ?? accountId
2725
- });
2741
+ };
2742
+ finding.source = getSecurityHubSource(finding);
2743
+ findings.push(finding);
2726
2744
  }
2727
2745
  nextToken = resp.NextToken;
2728
2746
  } while (nextToken);
@@ -7016,11 +7034,24 @@ function generateMlps3Report(scanResults, lang) {
7016
7034
  function esc(s) {
7017
7035
  return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
7018
7036
  }
7037
+ function safeUrl(url) {
7038
+ try {
7039
+ const u = new URL(url);
7040
+ if (u.protocol === "https:" || u.protocol === "http:") return url;
7041
+ return null;
7042
+ } catch {
7043
+ return null;
7044
+ }
7045
+ }
7019
7046
  function escWithLinks(s) {
7020
7047
  const parts = s.split(/(https?:\/\/\S+)/);
7021
7048
  return parts.map((part, i) => {
7022
7049
  if (i % 2 === 1) {
7023
- return `<a href="${esc(part)}" style="color:#60a5fa" target="_blank" rel="noopener">${esc(part)}</a>`;
7050
+ const safe = safeUrl(part);
7051
+ if (safe) {
7052
+ return `<a href="${esc(safe)}" style="color:#60a5fa" target="_blank" rel="noopener">${esc(part)}</a>`;
7053
+ }
7054
+ return esc(part);
7024
7055
  }
7025
7056
  return esc(part);
7026
7057
  }).join("");
@@ -7046,18 +7077,6 @@ var SEVERITY_ORDER2 = ["CRITICAL", "HIGH", "MEDIUM", "LOW"];
7046
7077
  function getRecommendationTemplate(rem) {
7047
7078
  return rem.replace(/\b(i-[0-9a-f]+)\b/g, "{instance}").replace(/\b(vol-[0-9a-f]+)\b/g, "{volume}").replace(/\b(sg-[0-9a-f]+)\b/g, "{sg}").replace(/\b(eipalloc-[0-9a-f]+)\b/g, "{eip}").replace(/\b(arn:aws[-\w]*:[^"\s]+)\b/g, "{arn}").replace(/"[^"]+"/g, "{name}").replace(/bucket \S+/g, "bucket {name}").replace(/instance \S+/g, "instance {id}").replace(/volume \S+/g, "volume {id}").replace(/rule \S+/g, "rule {name}");
7048
7079
  }
7049
- function getSecurityHubSource(finding) {
7050
- const impact = finding.impact ?? "";
7051
- const match = impact.match(/^Source:\s*([^(]+)/);
7052
- if (!match) return "Other";
7053
- const product = match[1].trim();
7054
- if (product === "Security Hub" || product.includes("Foundational")) return "FSBP";
7055
- if (product === "Inspector" || product.includes("Inspector")) return "Inspector";
7056
- if (product === "GuardDuty" || product.includes("GuardDuty")) return "GuardDuty";
7057
- if (product === "Config" || product.includes("Config")) return "Config";
7058
- if (product === "IAM Access Analyzer" || product.includes("Access Analyzer")) return "Access Analyzer";
7059
- return "Other";
7060
- }
7061
7080
  var SECURITY_HUB_SUB_CAT_ORDER = ["FSBP", "Inspector", "GuardDuty", "Config", "Access Analyzer", "Other"];
7062
7081
  function scoreColor(score) {
7063
7082
  if (score >= 80) return "#22c55e";
@@ -7253,6 +7272,7 @@ function sharedCss() {
7253
7272
  .filter-count{color:#64748b;font-size:13px;margin-left:auto}
7254
7273
  @media print{
7255
7274
  .filter-toolbar{display:none !important}
7275
+ .finding-card,.module-fold{display:block !important}
7256
7276
  body{background:#fff;color:#1e293b;-webkit-print-color-adjust:exact;print-color-adjust:exact}
7257
7277
  .container{max-width:100%;padding:20px}
7258
7278
  .card,.score-card,.stat-card,.chart-box,.finding-fold,.top5-card,.trend-chart,.category-fold,.module-fold,.finding-card,.rec-fold{background:#fff;border:1px solid #e2e8f0}
@@ -7759,7 +7779,8 @@ ${rest}
7759
7779
  const renderRec = (r) => {
7760
7780
  const sev = r.severity.toLowerCase();
7761
7781
  const countLabel = r.count > 1 ? ` (&times; ${r.count})` : "";
7762
- const linkHtml = r.url ? ` <a href="${esc(r.url)}" style="color:#60a5fa" target="_blank" rel="noopener">&#128214;</a>` : "";
7782
+ const safeLink = r.url ? safeUrl(r.url) : null;
7783
+ const linkHtml = safeLink ? ` <a href="${esc(safeLink)}" style="color:#60a5fa" target="_blank" rel="noopener">&#128214;</a>` : "";
7763
7784
  return `<li><span class="badge badge-${esc(sev)}">${esc(r.severity)}</span> ${esc(r.text)}${countLabel}${linkHtml}</li>`;
7764
7785
  };
7765
7786
  const TOP_N = 10;
@@ -7795,7 +7816,8 @@ ${remaining.map(renderRec).join("\n")}
7795
7816
  document.querySelectorAll('.module-fold').forEach(function(f){
7796
7817
  var mod=f.getAttribute('data-module');
7797
7818
  if(activeMod!=='ALL'&&mod!==activeMod){f.style.display='none';return;}
7798
- f.style.display='';
7819
+ var hasVisible=f.querySelectorAll('.finding-card:not([style*="display: none"])').length>0;
7820
+ f.style.display=hasVisible?'':'none';
7799
7821
  });
7800
7822
  document.querySelectorAll('.severity-group-fold').forEach(function(g){
7801
7823
  g.style.display=g.querySelectorAll('.finding-card:not([style*="display: none"])').length?'':'none';
@@ -7917,7 +7939,6 @@ function generateMlps3HtmlReport(scanResults, history, lang) {
7917
7939
  </section>`;
7918
7940
  }
7919
7941
  const isEn = (lang ?? "zh") === "en";
7920
- const itemCat = (r) => isEn ? r.item.categoryEn : r.item.categoryCn;
7921
7942
  const itemControl = (r) => isEn ? r.item.controlEn : r.item.controlCn;
7922
7943
  const itemReq = (r) => isEn ? r.item.requirementEn : r.item.requirementCn;
7923
7944
  const categoryMap = /* @__PURE__ */ new Map();
@@ -8119,7 +8140,8 @@ ${itemsHtml}
8119
8140
  const renderMlpsRec = (r) => {
8120
8141
  const sev = r.severity.toLowerCase();
8121
8142
  const countLabel = r.count > 1 ? ` (&times; ${r.count})` : "";
8122
- const linkHtml = r.url ? ` <a href="${esc(r.url)}" style="color:#60a5fa" target="_blank" rel="noopener">&#128214;</a>` : "";
8143
+ const safeLink = r.url ? safeUrl(r.url) : null;
8144
+ const linkHtml = safeLink ? ` <a href="${esc(safeLink)}" style="color:#60a5fa" target="_blank" rel="noopener">&#128214;</a>` : "";
8123
8145
  return `<li><span class="badge badge-${esc(sev)}">${esc(r.severity)}</span> ${esc(r.text)}${countLabel}${linkHtml}</li>`;
8124
8146
  };
8125
8147
  const MLPS_TOP_N = 10;