Skip to main content
Glama
badchars

osint-mcp-server

by badchars

dns_email_security

Analyze email security posture by checking SPF, DMARC, and DKIM records with risk assessment and recommendations for domains.

Instructions

Analyze email security posture: SPF, DMARC, DKIM records with risk assessment and recommendations. Checks common DKIM selectors (google, selector1, selector2, k1, etc.).

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
domainYesDomain to analyze
dkim_selectorsNoCustom DKIM selectors to check (default: common selectors)

Implementation Reference

  • The handler function for dns_email_security that analyzes SPF, DMARC, and DKIM records to assess email security posture.
    export async function dnsEmailSecurity(domain: string, dkimSelectors?: string[]): Promise<EmailSecurityResult> {
      const selectors = dkimSelectors ?? DEFAULT_DKIM_SELECTORS;
      const recommendations: string[] = [];
    
      // SPF
      let spf: EmailSecurityResult["spf"] = { found: false, risk: "high" };
      try {
        const txts = await dns.resolveTxt(domain);
        const spfRecord = txts.map((t) => t.join("")).find((t) => t.startsWith("v=spf1"));
        if (spfRecord) {
          const includes = [...spfRecord.matchAll(/include:(\S+)/g)].map((m) => m[1]);
          let policy = "neutral";
          if (spfRecord.includes("-all")) policy = "hard_fail";
          else if (spfRecord.includes("~all")) policy = "soft_fail";
          else if (spfRecord.includes("+all")) policy = "pass_all";
          else if (spfRecord.includes("?all")) policy = "neutral";
    
          let risk = "low";
          if (policy === "pass_all") risk = "critical";
          else if (policy === "soft_fail") risk = "medium";
          else if (policy === "neutral") risk = "medium";
    
          if (policy === "soft_fail") recommendations.push("Upgrade SPF from ~all (soft fail) to -all (hard fail)");
          if (policy === "pass_all") recommendations.push("SPF +all allows any IP to send email — change to -all immediately");
    
          spf = { found: true, record: spfRecord, policy, includes, risk };
        } else {
          recommendations.push("No SPF record found — add v=spf1 with authorized senders");
          spf = { found: false, risk: "critical" };
        }
      } catch {
        spf = { found: false, risk: "high" };
      }
    
      // DMARC
      let dmarc: EmailSecurityResult["dmarc"] = { found: false, risk: "critical" };
      try {
        const txts = await dns.resolveTxt(`_dmarc.${domain}`);
        const dmarcRecord = txts.map((t) => t.join("")).find((t) => t.startsWith("v=DMARC1"));
        if (dmarcRecord) {
          const pMatch = dmarcRecord.match(/;\s*p=(\w+)/);
          const spMatch = dmarcRecord.match(/;\s*sp=(\w+)/);
          const ruaMatch = dmarcRecord.match(/;\s*rua=mailto:([^\s;]+)/);
          const policy = pMatch?.[1] ?? "none";
          const subdomainPolicy = spMatch?.[1];
          const rua = ruaMatch?.[1];
    
          let risk = "low";
          if (policy === "none") {
            risk = "high";
            recommendations.push("DMARC policy is p=none (monitoring only) — upgrade to p=quarantine then p=reject");
          } else if (policy === "quarantine") {
            risk = "medium";
          }
    
          dmarc = { found: true, record: dmarcRecord, policy, subdomain_policy: subdomainPolicy, rua, risk };
        } else {
          recommendations.push("No DMARC record found — add _dmarc TXT record with at least p=quarantine");
          dmarc = { found: false, risk: "critical" };
        }
      } catch {
        recommendations.push("No DMARC record found — add _dmarc TXT record with at least p=quarantine");
        dmarc = { found: false, risk: "critical" };
      }
    
      // DKIM
      const dkimResults: EmailSecurityResult["dkim"] = [];
      for (const selector of selectors) {
        try {
          const txts = await dns.resolveTxt(`${selector}._domainkey.${domain}`);
          const record = txts.map((t) => t.join("")).join("");
          let keySize: string | undefined;
          const pMatch = record.match(/p=([A-Za-z0-9+/=]+)/);
          if (pMatch) {
            const keyBytes = Math.ceil((pMatch[1].length * 3) / 4);
            const bits = keyBytes * 8;
            keySize = `${bits}-bit`;
            if (bits <= 1024) {
              recommendations.push(`DKIM selector "${selector}" uses ${bits}-bit key — upgrade to 2048-bit minimum`);
            }
          }
          dkimResults.push({ selector, found: true, record, keySize });
        } catch {
          // Also try CNAME (common for Microsoft 365 DKIM)
          try {
            const cnames = await dns.resolveCname(`${selector}._domainkey.${domain}`);
            dkimResults.push({ selector, found: true, record: `CNAME → ${cnames[0]}` });
          } catch {
            dkimResults.push({ selector, found: false });
          }
        }
      }
    
      if (!dkimResults.some((d) => d.found)) {
        recommendations.push("No DKIM records found for any common selector — configure DKIM signing");
      }
    
      // Overall risk
      const risks = [spf.risk, dmarc.risk];
      let overallRisk: EmailSecurityResult["overallRisk"] = "low";
      if (risks.includes("critical")) overallRisk = "critical";
      else if (risks.includes("high")) overallRisk = "high";
      else if (risks.includes("medium")) overallRisk = "medium";
    
      return { domain, spf, dmarc, dkim: dkimResults, overallRisk, recommendations };
    }
  • Tool definition and registration for dns_email_security in the protocol tools file.
    const dnsEmailSecurityTool: ToolDef = {
      name: "dns_email_security",
      description: "Analyze email security posture: SPF, DMARC, DKIM records with risk assessment and recommendations. Checks common DKIM selectors (google, selector1, selector2, k1, etc.).",
      schema: {
        domain: z.string().describe("Domain to analyze"),
        dkim_selectors: z.array(z.string()).optional().describe("Custom DKIM selectors to check (default: common selectors)"),
      },
      execute: async (args) =>
        json(await dnsEmailSecurity(args.domain as string, args.dkim_selectors as string[] | undefined)),
    };

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/badchars/osint-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server