<?xml version='1.0' encoding='UTF-8'?>
<rfc xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" category="info" docName="draft-grimminck-safe-ioc-sharing-10" ipr="trust200902" xml:lang="en" version="3" submissionType="independent">
  <front>
    <title abbrev="Safe-IOC Sharing">Safe and Reversible Sharing of Malicious URLs and Indicators</title>
    <author fullname="Stefan Grimminck" role="editor">
      <address>
        <email>ietf@stefangrimminck.nl</email>
      </address>
    </author>
    <date year="2026" month="April" day="30"/>
    <abstract>
      <t>This document codifies a consistent and reversible convention used in the threat intelligence and security communities for sharing potentially malicious indicators of compromise (IOCs), such as URLs, IP addresses, email addresses, and domain names. It describes a safe obfuscation format that reduces the risk of accidental execution or activation when IOCs are displayed or transmitted. The recommended form brackets the URI scheme name so that the string is not syntactically a valid URI per generic URI parsers, and extends the same bracket treatment to colons inside IPv6 literals; recognizable nested indicators within the Path, Query, or Fragment of a URI are obfuscated in place, and legacy scheme-substitution tokens are defined for de-obfuscation interoperability. Safe-IOC strings are a textual rendering convention, not URIs, and are not intended to be processed by generic URI parsers. These conventions aim to improve interoperability among tools and feeds that exchange threat intelligence data.</t>
    </abstract>
  </front>
  <middle>
    <section title="Introduction">
      <t>This document is an Informational specification published as an Independent Submission to the RFC series. It is not an Internet Standard and does not represent the consensus of the Internet Engineering Task Force (IETF) or any of its working groups.</t>
      <t>The purpose of this document is to define a single transformation that converts a URL, IP address, domain name, or email address into an inert textual rendering, together with the inverse transformation that recovers the original value. Specifying both directions enables interoperability among the systems that produce, transport, or consume these renderings while preventing accidental activation by general-purpose software that handles them in transit.</t>
      <t>The secure sharing of malicious artifacts is vital to threat intelligence, open-source intelligence (OSINT), and incident response. However, sharing raw URLs, IP addresses, and email addresses associated with malware or threat actors poses a risk of accidental activation.</t>
      <t>Participants who routinely share indicators of compromise (IOCs) include security operations center (SOC) analysts, computer security incident response teams (CSIRTs), OSINT researchers, incident responders, and vendors of threat intelligence platforms and feeds. IOCs appear in email threads, instant-messaging channels, ticketing systems, PDF and HTML reports, blog posts, paste sites, machine-readable formats such as STIX <xref target="STIX21"/> / TAXII <xref target="TAXII21"/>, and platforms such as MISP <xref target="MISP"/>. Both human readers and automated pipelines consume this material.</t>
      <t>When a raw URI such as "https://malicious-host.example/path" is embedded in those channels, many systems automatically detect it and render it as a clickable or otherwise actionable link. An analyst may then activate the resource unintentionally: navigating to an attacker-controlled URI can reveal the analyst's IP address and organizational affiliation, trigger delivery of malware, or alert the threat actor that a particular indicator is under active investigation. Some mail and web infrastructure pre-fetches or resolves links for scanning or preview purposes, producing the same exposure without any deliberate user action. PDF viewers and rich-text editors may turn strings that resemble URIs into hyperlinks even when the author intended plain text.</t>
      <t>A longstanding practice in the security community is to alter IOCs so that they remain human-readable but are not treated as live URIs by typical software: for example, replacing "." with "[.]" and wrapping the scheme name in brackets so that "http" becomes "[http]". Older conventions substituted characters within the scheme name (e.g., "http" to "hxxp"), but many variant spellings emerged (e.g., "h**p", "hXXp"), hindering reliable parsing and automation. This document defines a canonical form that uses uniform square-bracket wrapping for the scheme, dot, at-sign, and (inside IPv6 literals) colon delimiters, and a strict order of operations so that independent implementations can interoperate. Legacy scheme substitutions ("hxxp", "hxxps") are documented for de-obfuscation interoperability but are NOT RECOMMENDED for new output.</t>
      <t>Safe-IOC strings produced by this specification are a textual rendering convention intended for human consumption and for lossy text channels. They are deliberately not valid URIs per <xref target="RFC3986"/> and are not intended to be passed to generic URI parsers, resolvers, or dereferencing libraries.</t>
      <t>The canonical "[scheme]" form does not occupy the URI scheme namespace (see <xref target="canonical"/>). The legacy tokens "hxxp" and "hxxps" do occupy that syntactic position. The security implications are discussed in <xref target="security"/>. Implementations MUST NOT treat any obfuscated form as a resolvable URI scheme.</t>
      <t>The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 <xref target="RFC2119"/> <xref target="RFC8174"/> when, and only when, they appear in all capitals, as shown here.</t>
    </section>

    <section title="Terminology">
      <t><strong>Obfuscating:</strong> The process of altering an indicator so that it cannot be accidentally activated or clicked. The goal is to prevent automatic execution or resolution, not to conceal the content from human readers; the original indicator remains visually recognizable.</t>
      <t><strong>De-obfuscating:</strong> The process of restoring an obfuscated indicator to its original, actionable form.</t>
      <t><strong>IOC:</strong> Indicator of Compromise - data such as a URL, IP address, domain name, email address, or hash associated with malicious activity.</t>
      <t><strong>IP-literal:</strong> The bracketed form of an IPv6 address as it appears in a URI authority component (e.g., "[2001:db8::1]"), per Section 3.2.2 of <xref target="RFC3986"/>.</t>
      <t><strong>Nested Indicator:</strong> A URI, email address, or IP address literal that appears inside the Path, Query, or Fragment of another URI (for example, an open-redirect target carried as a query parameter, or an email address embedded in a redirect URL).</t>
    </section>

    <section title="Problem Statement">
      <t>Inconsistent obfuscation practices hinder the reliable and automated exchange of threat intelligence. For example:</t>
      <ul>
        <li>A URL obfuscated as "h**p://example[.]example" cannot be reliably parsed by tools expecting "[http]://example[.]example".</li>
        <li>An IP address obfuscated with parentheses (e.g., "192.0.2(.)1") may fail to de-obfuscate in systems expecting "[.]".</li>
        <li>An IPv6 literal left in colon-hexadecimal form (e.g., "[2001:db8::1]") remains parseable by URI libraries and may be auto-linked by document viewers, mail clients, and terminal emulators, producing the same activation risk that "[.]" substitution addresses for IPv4 and domain names.</li>
      </ul>
      <t>Such inconsistencies reduce the effectiveness of threat detection and response.</t>
    </section>

    <section title="Canonical Transformation Rule" anchor="canonical">
      <t>To prevent double-bracketing (e.g., "[[https]]://example[[.]]example") when a tool processes the same string twice or in the wrong order, implementations MUST apply transformations in the following strict order of operations. Implementations MUST treat already-obfuscated substrings (the tokens "[scheme]", "[.]", "[@]", and "[:]") as opaque and MUST NOT apply transformations to them again; thus, the transformation is idempotent.</t>
      <t>Percent-encoding is handled as follows. Percent-encoded delimiters in the Host or Userinfo of an input URI (for example, "%2e" for ".") MAY be decoded to their literal form before Steps 2 and 3 are applied; the resulting literal characters are then bracketed by those steps. The output of the transformation MUST NOT itself contain percent-encoded forms of the bracketed delimiters: an obfuscator that does not decode percent-encoded delimiters in the input MUST leave them as percent-encoded sequences in the output rather than emit token-like strings such as "[%2e]". Percent-encoded content inside a Path, Query, or Fragment MUST NOT be decoded during obfuscation, so that independent implementations produce the same output for the same input.</t>

      <section title="Step 1: Scheme">
        <t>Identify the URI scheme and wrap it in square brackets. For example, "http" becomes "[http]", "https" becomes "[https]", "ftp" becomes "[ftp]". The leading "[" character is not permitted in a URI scheme name (Section 3.1 of <xref target="RFC3986"/>), so the result cannot be mistaken for a valid URI by compliant parsers. Because the transformation is purely syntactic wrapping, it extends to any current or future scheme without requiring a per-scheme mapping table. Only the scheme name is wrapped; the scheme delimiter ("://" for hierarchical URIs, ":" for schemes such as mailto: or tel:) is preserved unchanged. The case of the scheme name is preserved verbatim so that the transformation is reversible byte-for-byte; applications that require case-folded schemes can normalize before or after applying this transformation.</t>
        <t>The legacy tokens "hxxp" and "hxxps" are in widespread operational use as obfuscated forms of "http" and "https" respectively. Implementations encountering these tokens in existing data SHOULD recognize them as obfuscated indicators during de-obfuscation (see <xref target="deobfuscation"/>). These legacy forms are NOT RECOMMENDED for new output. No other legacy substitutions (e.g., "h**p", "fxxps") are defined by this specification.</t>
      </section>

      <section title="Step 2: Userinfo">
        <t>Identify the "@" symbol in the userinfo subcomponent (per <xref target="RFC3986"/>) and replace it with "[@]". This applies to email addresses and URIs containing userinfo (e.g., "username:password@host").</t>
      </section>

      <section title="Step 3: Host" anchor="step-host">
        <t>Replace all "." (period) characters in the Host subcomponent with "[.]". This applies to domain names and IPv4 addresses, including standalone values (e.g., "evil.example" or "198.51.100.1" without a scheme). IPv4 addresses use dotted-decimal notation that overlaps with domain name syntax, so the "[.]" substitution applies to them naturally. Inside an IPv6 literal, replace every ":" (colon) with "[:]"; if the literal contains an embedded IPv4 address (e.g., "::ffff:192.0.2.1" per Section 2.5.5 of <xref target="RFC4291"/>), each "." in that embedded IPv4 MUST also be replaced with "[.]". The outer square brackets that surround an IP-literal in URI syntax (Section 3.2.2 of <xref target="RFC3986"/>) are part of the URI grammar, not part of the obfuscation, and MUST be preserved verbatim. Port numbers following the host (e.g., ":8080" or the port following an IP-literal) are not part of the Host subcomponent and MUST NOT be altered.</t>
        <t>Zone identifiers (per <xref target="RFC4007"/>) may appear attached to an IPv6 address as the "%&lt;zone-id&gt;" suffix in bare form, or as the "%25&lt;zone-id&gt;" suffix inside a URI IP-literal. The URI-literal encoding was originally defined in <xref target="RFC6874"/>, which has since been obsoleted by <xref target="RFC9844"/> without a replacement URI syntax; the "%25&lt;zone-id&gt;" form remains in operational use and is treated here as the de facto encoding. Whichever form is present is preserved verbatim by this transformation.</t>
        <t>Bare IPv6 literals without surrounding URI brackets (e.g., "2001:db8::1" appearing on its own line in a report) MUST receive the same colon-bracketing treatment. Implementations SHOULD recognize bare IPv6 by the presence of either a "::" shorthand or the fully expanded eight-group colon-hexadecimal form so that strings such as "host:port" (a single colon) are not misclassified. Intermediate forms (more than one colon but neither a "::" shorthand nor a full eight-group expansion, e.g., a malformed "2001:db8:1:2:3:4:5") are not recognized as IPv6 by this rule and are left unchanged.</t>
        <t>For schemes whose content after the scheme delimiter is not a hierarchical authority (e.g., "mailto:" per <xref target="RFC6068"/>, or "urn:"), implementations apply Step 2 to every "@" and Step 3 to every "." within the scheme body, up to the first "?" or "#" delimiter.</t>
        <t>When a scheme is present, host subcomponent boundaries are determined by the URI syntax defined in <xref target="RFC3986"/>. For bare indicators without a scheme (e.g., a standalone domain or IP address), host identification is implementation-dependent; implementations SHOULD apply reasonable heuristics such as recognizing dotted-decimal IPv4 addresses, colon-hexadecimal IPv6 addresses, and domain-name patterns.</t>
      </section>

      <section title="Step 4: Nested Indicators">
        <t>Implementations MUST NOT apply Steps 2 and 3 wholesale to the Path, Query, or Fragment of the primary URI; doing so would alter semantics (for example, by bracketing dots in file extensions or query values) and is not reversible without ambiguity.</t>
        <t>Implementations locate nested indicators by scanning the literal (undecoded) text of the Path, Query, and Fragment for spans matching one of the grammars listed below; each matched span is obfuscated in place by recursively applying Steps 1 through 3. Percent-encoded nested indicators are not matched by this step, and implementations that wish to surface them SHOULD emit them as separate obfuscated indicators. For the purposes of this step, a nested indicator is one of the following:</t>
        <ul>
          <li>A URI with a scheme (including "mailto:" URIs).</li>
          <li>A bare email address (an addr-spec per Section 3.4.1 of <xref target="RFC5322"/>).</li>
          <li>A bare IPv4 or IPv6 address literal.</li>
        </ul>
        <t>Only spans matching one of the grammars above are obfuscated; dots, "@", and ":" characters that appear elsewhere in the Path, Query, or Fragment MUST be preserved verbatim.</t>
        <t>Implementations MAY instead extract each nested indicator and emit it as a separate obfuscated indicator alongside the primary one.</t>
      </section>
    </section>

    <section title="Formal ABNF Grammar" anchor="abnf">
      <t>The following uses Augmented BNF (ABNF) per <xref target="RFC5234"/> to define the tokens used in obfuscated IOC strings. The scheme production matches the syntax in Section 3.1 of <xref target="RFC3986"/>. An implementation MAY use this grammar to validate whether a string is already obfuscated or still requires processing.</t>
      <figure anchor="safe-ioc-abnf">
        <sourcecode type="abnf" name="safe-ioc-abnf"><![CDATA[safe-scheme    = "[" scheme "]"
scheme         = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
legacy-scheme  = "hxxp" / "hxxps"
safe-dot       = "[" "." "]"
safe-at        = "[" "@" "]"
safe-colon     = "[" ":" "]"

obf-label      = 1*( ALPHA / DIGIT / "-" )
obf-host       = obf-label 1*( safe-dot obf-label )
obf-local      = 1*( ALPHA / DIGIT / "." / "_" / "%"
                     / "+" / "-" )
obf-email      = obf-local safe-at obf-host]]></sourcecode>
      </figure>
      <t>The obf-label production permits any character allowed in a DNS label but does not enforce DNS label structure rules; applications that will resolve the recovered host SHOULD additionally enforce the no-leading-or-trailing-hyphen and 63-octet-maximum rules per Section 3.5 of <xref target="RFC1035"/>. The obf-host production matches a host of two or more labels; a single-label host has no dots to bracket and is left unchanged by Step 3. The composition of a full URI (scheme, authority, path, query, fragment) and of an obfuscated IPv6 literal is not restated here; both are defined algorithmically in <xref target="canonical"/> and rely on the URI grammar of <xref target="RFC3986"/> and the address grammar of <xref target="RFC4291"/>.</t>
      <t>A compliant implementation MUST recognize a string as obfuscated when it contains any of the tokens safe-scheme, legacy-scheme, safe-dot, safe-at, or safe-colon in the roles described in this document.</t>
    </section>

    <section title="De-obfuscation Techniques" anchor="deobfuscation">
      <t>Tools designed to ingest obfuscated data SHOULD automatically reverse these transformations in a deterministic manner:</t>
      <ul>
        <li>Strip enclosing brackets from "[scheme]" to recover the original scheme name (e.g., "[https]" becomes "https").</li>
        <li>Convert legacy token "hxxps" back to "https".</li>
        <li>Convert legacy token "hxxp" back to "http".</li>
        <li>Convert "[.]" back to ".".</li>
        <li>Convert "[@]" back to "@".</li>
        <li>Convert "[:]" back to ":".</li>
      </ul>
      <t>The substitutions listed above are non-overlapping and may be applied in any order, with one exception: for legacy tokens, longer strings MUST be reversed before shorter prefixes that are substrings of them (e.g., reverse "hxxps" before "hxxp"). De-obfuscation MUST maintain the original semantics of the data to avoid misinterpretation.</t>
      <t>Safe-IOC strings may contain two kinds of square brackets: the URI IP-literal brackets (Section 3.2.2 of <xref target="RFC3986"/>) and the obfuscation tokens "[scheme]", "[.]", "[@]", and "[:]". When an IPv6 URI is obfuscated, adjacent "[" or "]" characters may appear (e.g., "[http]://[[:][:]1]"). These are adjacent tokens, not nested brackets. Parsers SHOULD tokenize left-to-right, attempting to match the obfuscation tokens first and treating any remaining "[" or "]" as a URI IP-literal delimiter.</t>

      <section title="Safety Check for Reversibility" anchor="safety-check">
        <t>De-obfuscation MUST only be performed when the output is written to a non-executable buffer (e.g., a variable, string, or file) that cannot be automatically interpreted, executed, or rendered as a clickable link by the system or application. The tool MUST NOT de-obfuscate a string if it is currently being rendered in a "live" environment (e.g., a web browser preview, an active document viewer, or any context where the resulting string could be automatically executed, resolved, or displayed as a clickable link).</t>
        <t>De-obfuscation SHOULD only occur in controlled contexts such as:</t>
        <ul>
          <li>Command-line tools with explicit user confirmation</li>
          <li>Isolated analysis environments (sandboxes)</li>
          <li>Backend processing pipelines that do not render output to users</li>
        </ul>
      </section>
    </section>

    <section title="Example Use Cases">
      <t>Common scenarios include:</t>
      <ul>
        <li><strong>OSINT Sharing:</strong> A report lists obfuscated URLs (e.g., "[http]://malware[.]example/payload") to prevent accidental clicks.</li>
        <li><strong>Email Communication:</strong> Security teams share obfuscated IOCs like "attacker[@]example[.]example" or "[mailto]:attacker[@]example[.]com" in email threads.</li>
        <li><strong>Threat Intelligence Platforms:</strong> Automated ingestion of obfuscated IPs (e.g., "192[.]0[.]2[.]1" or "[http]://[2001[:]db8[:][:]1]:8080/") for blocklist updates.</li>
      </ul>
      <t>Safe-IOC strings are intended for human-readable contexts (reports, email, tickets, chat) and for free-text fields in structured formats such as STIX 2.1 <xref target="STIX21"/>; they are not a substitute for the typed observable and indicator objects those formats provide.</t>
    </section>

    <section title="Implementation Guidance">
      <t>Software designed to parse threat intelligence feeds should explicitly support these obfuscation and de-obfuscation conventions. Implementations SHOULD verify correct behavior through unit tests and validation scripts using the test vectors in <xref target="test-vectors"/>.</t>
    </section>

    <section title="Edge Cases and Special Handling">
      <t><strong>Internationalized Domain Names (IDNs):</strong> Apply Step 3 to the IDN as presented, in either A-label (ASCII-Compatible Encoding, "xn--" prefixed) or U-label (native Unicode) form per <xref target="RFC5890"/>; for example, "xn--n3h.example" becomes "xn--n3h[.]example".</t>
      <t><strong>Non-Standard URI Schemes:</strong> The "[scheme]" canonical form extends to any URI scheme. For example, "smb://fileserver.example/share" becomes "[smb]://fileserver[.]example/share".</t>
      <t><strong>IPv6 Literals in URIs:</strong> Bracket every ":" inside the IP-literal as "[:]" and every "." in any embedded IPv4 portion as "[.]". Preserve the outer URI brackets, any "%25&lt;zone-id&gt;" suffix, and any following port. For example, "http://[2001:db8::1]:8080" becomes "[http]://[2001[:]db8[:][:]1]:8080", and "[::ffff:192.0.2.1]" becomes "[[:][:]ffff[:]192[.]0[.]2[.]1]". The "[[" and "]]" sequences that appear when an IP-literal begins or ends with "::" are adjacent tokens, not nested brackets.</t>
      <t><strong>Bare IPv6 Literals:</strong> Addresses appearing without URI brackets (e.g., "2001:db8::1" on its own line) are obfuscated by colon-bracketing alone: "2001[:]db8[:][:]1". Implementations SHOULD restrict bare-IPv6 detection to strings that contain "::" or the fully expanded eight-group form so that "host:port" and similar single-colon constructs are not misclassified.</t>
    </section>

    <section title="Test Vectors" anchor="test-vectors">
      <t>The following provides a "golden set" of inputs and expected outputs in JSON form, intended to be consumed directly by automated test harnesses. Each entry has a "label", an "input", an "operation" ("obfuscate" for the forward transformation defined in <xref target="canonical"/>, "deobfuscate" for the inverse transformation defined in <xref target="deobfuscation"/>), and the "expected" output. Domain names use the "example" reserved space per <xref target="RFC2606"/>; IPv4 addresses use documentation ranges per <xref target="RFC5737"/>; IPv6 addresses use the documentation prefix per <xref target="RFC3849"/>.</t>
      <t>The vectors fall into four groups. The forward URI rows (standard-url through scheme-case-preserved) exercise Steps 1 through 3 on full URIs and on bare indicators, including IPv4, IPv6 in every form covered by <xref target="step-host"/>, zone identifiers, userinfo, and ports. The Step 4 rows (nested-url-in-query, nested-email-in-query) exercise in-place obfuscation of nested indicators. The idempotency rows confirm that applying the transformation to already-obfuscated input produces no change. The deobfuscate rows exercise the inverse transformation defined in <xref target="deobfuscation"/>, including the legacy "hxxps" recognition rule.</t>
      <figure anchor="safe-ioc-vectors">
        <sourcecode type="json" name="safe-ioc-vectors.json"><![CDATA[[
  {"label": "standard-url", "operation": "obfuscate",
   "input": "https://bad.example",
   "expected": "[https]://bad[.]example"},
  {"label": "url-with-path", "operation": "obfuscate",
   "input": "https://evil.example/path",
   "expected": "[https]://evil[.]example/path"},
  {"label": "deep-link-url", "operation": "obfuscate",
   "input": "https://bad.example/path/to/page?q=1#frag",
   "expected": "[https]://bad[.]example/path/to/page?q=1#frag"},
  {"label": "http-url", "operation": "obfuscate",
   "input": "http://attacker.example",
   "expected": "[http]://attacker[.]example"},
  {"label": "ftp-url", "operation": "obfuscate",
   "input": "ftp://files.example/",
   "expected": "[ftp]://files[.]example/"},
  {"label": "mailto", "operation": "obfuscate",
   "input": "mailto:user@example.com",
   "expected": "[mailto]:user[@]example[.]com"},
  {"label": "ipv4-address", "operation": "obfuscate",
   "input": "198.51.100.1",
   "expected": "198[.]51[.]100[.]1"},
  {"label": "ipv4-in-url", "operation": "obfuscate",
   "input": "http://192.0.2.1",
   "expected": "[http]://192[.]0[.]2[.]1"},
  {"label": "ipv6-in-url", "operation": "obfuscate",
   "input": "http://[2001:db8::1]:8080",
   "expected": "[http]://[2001[:]db8[:][:]1]:8080"},
  {"label": "ipv6-full-form", "operation": "obfuscate",
   "input": "http://[2001:db8:0:0:0:0:0:1]/",
   "expected": "[http]://[2001[:]db8[:]0[:]0[:]0[:]0[:]0[:]1]/"},
  {"label": "ipv4-mapped-ipv6", "operation": "obfuscate",
   "input": "http://[::ffff:192.0.2.1]",
   "expected": "[http]://[[:][:]ffff[:]192[.]0[.]2[.]1]"},
  {"label": "ipv6-with-zone-id", "operation": "obfuscate",
   "input": "http://[2001:db8::1%25eth0]/",
   "expected": "[http]://[2001[:]db8[:][:]1%25eth0]/"},
  {"label": "bare-ipv6", "operation": "obfuscate",
   "input": "2001:db8::1",
   "expected": "2001[:]db8[:][:]1"},
  {"label": "bracketed-bare-ipv6", "operation": "obfuscate",
   "input": "[2001:db8::1]",
   "expected": "[2001[:]db8[:][:]1]"},
  {"label": "bare-ipv6-with-zone", "operation": "obfuscate",
   "input": "2001:db8::1%eth0",
   "expected": "2001[:]db8[:][:]1%eth0"},
  {"label": "email-address", "operation": "obfuscate",
   "input": "phish@target.example",
   "expected": "phish[@]target[.]example"},
  {"label": "punycode-domain", "operation": "obfuscate",
   "input": "xn--n3h.example",
   "expected": "xn--n3h[.]example"},
  {"label": "url-with-userinfo", "operation": "obfuscate",
   "input": "http://user:pass@attacker.example",
   "expected": "[http]://user:pass[@]attacker[.]example"},
  {"label": "bare-domain-with-port", "operation": "obfuscate",
   "input": "evil.example:443",
   "expected": "evil[.]example:443"},
  {"label": "scheme-case-preserved", "operation": "obfuscate",
   "input": "HTTPS://bad.example",
   "expected": "[HTTPS]://bad[.]example"},
  {"label": "nested-url-in-query", "operation": "obfuscate",
   "input":
     "http://example.com/r?url=http://evil.example",
   "expected":
     "[http]://example[.]com/r?url=[http]://evil[.]example"},
  {"label": "nested-email-in-query", "operation": "obfuscate",
   "input":
     "http://example.com/?contact=abuse@evil.example",
   "expected":
     "[http]://example[.]com/?contact=abuse[@]evil[.]example"},
  {"label": "idempotency-check", "operation": "obfuscate",
   "input": "[https]://bad[.]example",
   "expected": "[https]://bad[.]example"},
  {"label": "ipv6-idempotency", "operation": "obfuscate",
   "input": "[http]://[2001[:]db8[:][:]1]:8080",
   "expected": "[http]://[2001[:]db8[:][:]1]:8080"},
  {"label": "legacy-deobfuscation", "operation": "deobfuscate",
   "input": "hxxps://bad[.]example",
   "expected": "https://bad.example"},
  {"label": "legacy-deobfuscation-bare", "operation": "deobfuscate",
   "input": "hxxps://bad.example",
   "expected": "https://bad.example"},
  {"label": "case-preserved-roundtrip", "operation": "deobfuscate",
   "input": "[HTTPS]://bad[.]example",
   "expected": "HTTPS://bad.example"},
  {"label": "ipv6-uri-deobfuscation", "operation": "deobfuscate",
   "input": "[http]://[2001[:]db8[:][:]1]:8080",
   "expected": "http://[2001:db8::1]:8080"},
  {"label": "mailto-deobfuscation", "operation": "deobfuscate",
   "input": "[mailto]:user[@]example[.]com",
   "expected": "mailto:user@example.com"}
]]]></sourcecode>
      </figure>
    </section>

    <section title="Security Considerations" anchor="security">
      <t>While these obfuscation techniques reduce the risk of accidental activation, systems processing obfuscated indicators SHOULD apply the safeguards described in this section.</t>

      <section title="Relationship to the URI Scheme Registry">
        <t>The canonical "[scheme]" form does not occupy the URI scheme namespace (see <xref target="canonical"/>). Software that encounters bracketed schemes MUST NOT attempt to resolve or dereference them.</t>
        <t>The legacy tokens "hxxp" and "hxxps" do occupy the syntactic position of a URI scheme. Provisional entries for both names appear in the "Uniform Resource Identifier (URI) Schemes" registry per <xref target="RFC7595"/>. Implementations should consider surrounding context when disambiguating these tokens.</t>
      </section>

      <section title="Partial Obfuscation">
        <t>When a scheme is present, a compliant tool MUST obfuscate both the scheme (Step 1) and the host-level delimiters (Steps 2-3). Partial obfuscation (for example, replacing only "." with "[.]" while leaving "https" unchanged) creates a false sense of security: the scheme remains active and could still trigger automatic linkification or execution. Implementations MUST NOT produce partially obfuscated output when full obfuscation is intended. For bare indicators without a scheme (e.g., a standalone IP address or email address), host-level and userinfo obfuscation (Steps 2-3) alone constitutes valid Safe-IOC output.</t>
      </section>

      <section title="Parser Confusion">
        <t>Implementations that parse Safe-IOC strings may become confused by malformed or inconsistently obfuscated input. For example, "[https]://example.example" (scheme obfuscated but dots not) or "https://example[.]example" (dots obfuscated but scheme not) are not canonical Safe-IOC output and SHOULD be treated as partially obfuscated: such strings retain activation risk and implementations SHOULD either complete the obfuscation before display or flag the input as non-conforming.</t>
      </section>

      <section title="De-obfuscation in Non-Executable Contexts">
        <t>The non-executable-buffer requirement on de-obfuscation is stated normatively in <xref target="safety-check"/>. A non-executable buffer is one that cannot be automatically interpreted by the system (for example, as a URI to fetch, a command to run, or a link to display). Writing de-obfuscated output into a live document, rich-text editor, or browser address bar before explicit user action creates an unacceptable risk of accidental activation.</t>
      </section>

      <section title="Additional Considerations">
        <ul>
          <li>Implementations that do not follow the canonical transformation rule (e.g., by not treating "[.]", "[@]", and "[:]" as opaque) MAY produce nested or non-reversible output when obfuscation is applied repeatedly.</li>
          <li>Obfuscated URLs in PDFs may still be rendered as hyperlinks; use plain-text formatting.</li>
          <li>Systems processing obfuscated indicators MUST treat them as untrusted data, applying sandboxing or isolated environments for analysis.</li>
          <li>Credentials (e.g., <em>username:password</em>) SHOULD NOT be shared, even in obfuscated form, due to inherent security risks.</li>
          <li>Analysts accessing de-obfuscated indicators for investigation SHOULD do so within protected environments such as containers or dedicated analysis VMs to limit exposure to exploits.</li>
          <li>If a de-obfuscated indicator must be forwarded to a system that is not prepared to handle unsafe input, it SHOULD be re-obfuscated before being passed on.</li>
        </ul>
      </section>
    </section>

    <section title="IANA Considerations" anchor="iana">
      <t>This document has no IANA actions.</t>
      <t>[RFC Editor: Please remove this section before publication.]</t>
    </section>
  </middle>

  <back>
    <references>
      <name>References</name>
      <references>
        <name>Normative References</name>
        <reference anchor="RFC1035">
          <front>
            <title>Domain names - implementation and specification</title>
            <author initials="P." surname="Mockapetris" fullname="Paul Mockapetris"/>
            <date year="1987" month="November"/>
          </front>
          <seriesInfo name="STD" value="13"/>
          <seriesInfo name="RFC" value="1035"/>
        </reference>
        <reference anchor="RFC2119">
          <front>
            <title>Key words for use in RFCs to Indicate Requirement Levels</title>
            <author initials="S." surname="Bradner" fullname="Scott Bradner"/>
            <date year="1997" month="March"/>
          </front>
          <seriesInfo name="BCP" value="14"/>
          <seriesInfo name="RFC" value="2119"/>
        </reference>
        <reference anchor="RFC3986">
          <front>
            <title>Uniform Resource Identifier (URI): Generic Syntax</title>
            <author initials="T." surname="Berners-Lee" fullname="Tim Berners-Lee"/>
            <author initials="R." surname="Fielding" fullname="Roy T. Fielding"/>
            <author initials="L." surname="Masinter" fullname="Larry Masinter"/>
            <date year="2005" month="January"/>
          </front>
          <seriesInfo name="STD" value="66"/>
          <seriesInfo name="RFC" value="3986"/>
        </reference>
        <reference anchor="RFC4291">
          <front>
            <title>IP Version 6 Addressing Architecture</title>
            <author initials="R." surname="Hinden" fullname="Robert M. Hinden"/>
            <author initials="S." surname="Deering" fullname="Stephen E. Deering"/>
            <date year="2006" month="February"/>
          </front>
          <seriesInfo name="RFC" value="4291"/>
        </reference>
        <reference anchor="RFC5234">
          <front>
            <title>Augmented BNF for Syntax Specifications: ABNF</title>
            <author initials="D." surname="Crocker" fullname="Dave Crocker" role="editor"/>
            <author initials="P." surname="Overell" fullname="Paul Overell"/>
            <date year="2008" month="January"/>
          </front>
          <seriesInfo name="STD" value="68"/>
          <seriesInfo name="RFC" value="5234"/>
        </reference>
        <reference anchor="RFC5322">
          <front>
            <title>Internet Message Format</title>
            <author initials="P." surname="Resnick" fullname="Peter W. Resnick" role="editor"/>
            <date year="2008" month="October"/>
          </front>
          <seriesInfo name="RFC" value="5322"/>
        </reference>
        <reference anchor="RFC6068">
          <front>
            <title>The 'mailto' URI Scheme</title>
            <author initials="M." surname="Duerst" fullname="Martin Duerst"/>
            <author initials="L." surname="Masinter" fullname="Larry Masinter"/>
            <author initials="J." surname="Zawinski" fullname="Jamie Zawinski"/>
            <date year="2010" month="October"/>
          </front>
          <seriesInfo name="RFC" value="6068"/>
        </reference>
        <reference anchor="RFC7595">
          <front>
            <title>Guidelines and Registration Procedures for URI Schemes</title>
            <author initials="D." surname="Thaler" fullname="Dave Thaler" role="editor"/>
            <author initials="T." surname="Hansen" fullname="Tony Hansen"/>
            <author initials="T." surname="Hardie" fullname="Ted Hardie"/>
            <date year="2015" month="June"/>
          </front>
          <seriesInfo name="BCP" value="35"/>
          <seriesInfo name="RFC" value="7595"/>
        </reference>
        <reference anchor="RFC8174">
          <front>
            <title>Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words</title>
            <author initials="B." surname="Leiba" fullname="Barry Leiba"/>
            <date year="2017" month="May"/>
          </front>
          <seriesInfo name="BCP" value="14"/>
          <seriesInfo name="RFC" value="8174"/>
        </reference>
      </references>
      <references>
        <name>Informative References</name>
        <reference anchor="RFC4007">
          <front>
            <title>IPv6 Scoped Address Architecture</title>
            <author initials="S." surname="Deering" fullname="Stephen E. Deering"/>
            <author initials="B." surname="Haberman" fullname="Brian Haberman"/>
            <author initials="T." surname="Jinmei" fullname="Tatuya Jinmei"/>
            <author initials="E." surname="Nordmark" fullname="Erik Nordmark"/>
            <author initials="B." surname="Zill" fullname="Brian Zill"/>
            <date year="2005" month="March"/>
          </front>
          <seriesInfo name="RFC" value="4007"/>
        </reference>
        <reference anchor="RFC6874">
          <front>
            <title>Representing IPv6 Zone Identifiers in Address Literals and Uniform Resource Identifiers</title>
            <author initials="B." surname="Carpenter" fullname="Brian Carpenter"/>
            <author initials="S." surname="Cheshire" fullname="Stuart Cheshire"/>
            <author initials="R." surname="Hinden" fullname="Robert M. Hinden"/>
            <date year="2013" month="February"/>
          </front>
          <seriesInfo name="RFC" value="6874"/>
        </reference>
        <reference anchor="RFC9844">
          <front>
            <title>Entering IPv6 Zone Identifiers in User Interfaces</title>
            <author initials="B." surname="Carpenter" fullname="Brian Carpenter"/>
            <author initials="R." surname="Hinden" fullname="Robert M. Hinden"/>
            <date year="2025" month="August"/>
          </front>
          <seriesInfo name="RFC" value="9844"/>
        </reference>
        <reference anchor="RFC2606">
          <front>
            <title>Reserved Top Level DNS Names</title>
            <author initials="D." surname="Eastlake" fullname="Donald E. Eastlake 3rd"/>
            <author initials="A." surname="Panitz" fullname="Aliza R. Panitz"/>
            <date year="1999" month="June"/>
          </front>
          <seriesInfo name="BCP" value="32"/>
          <seriesInfo name="RFC" value="2606"/>
        </reference>
        <reference anchor="RFC3849">
          <front>
            <title>IPv6 Address Prefix Reserved for Documentation</title>
            <author initials="G." surname="Huston" fullname="Geoff Huston"/>
            <author initials="A." surname="Lord" fullname="Anne Lord"/>
            <author initials="P." surname="Smith" fullname="Philip Smith"/>
            <date year="2004" month="July"/>
          </front>
          <seriesInfo name="RFC" value="3849"/>
        </reference>
        <reference anchor="RFC5737">
          <front>
            <title>IPv4 Address Blocks Reserved for Documentation</title>
            <author initials="J." surname="Arkko" fullname="Jari Arkko"/>
            <author initials="M." surname="Cotton" fullname="Michelle Cotton"/>
            <author initials="L." surname="Vegoda" fullname="Leo Vegoda"/>
            <date year="2010" month="January"/>
          </front>
          <seriesInfo name="RFC" value="5737"/>
        </reference>
        <reference anchor="RFC5890">
          <front>
            <title>Internationalized Domain Names for Applications (IDNA): Definitions and Document Framework</title>
            <author initials="J." surname="Klensin" fullname="John C. Klensin"/>
            <date year="2010" month="August"/>
          </front>
          <seriesInfo name="RFC" value="5890"/>
        </reference>
        <reference anchor="STIX21" target="https://docs.oasis-open.org/cti/stix/v2.1/os/stix-v2.1-os.html">
          <front>
            <title>STIX Version 2.1</title>
            <author initials="B." surname="Jordan" fullname="Bret Jordan" role="editor"/>
            <author initials="R." surname="Piazza" fullname="Rich Piazza" role="editor"/>
            <author initials="T." surname="Darley" fullname="Trey Darley" role="editor"/>
            <date year="2021" month="June" day="10"/>
          </front>
          <seriesInfo name="OASIS Standard" value="stix-v2.1-os"/>
        </reference>
        <reference anchor="TAXII21" target="https://docs.oasis-open.org/cti/taxii/v2.1/os/taxii-v2.1-os.html">
          <front>
            <title>TAXII Version 2.1</title>
            <author initials="B." surname="Jordan" fullname="Bret Jordan" role="editor"/>
            <author initials="D." surname="Varner" fullname="Drew Varner" role="editor"/>
            <date year="2021" month="June" day="10"/>
          </front>
          <seriesInfo name="OASIS Standard" value="taxii-v2.1-os"/>
        </reference>
        <reference anchor="MISP" target="https://www.misp-project.org/">
          <front>
            <title>MISP - Malware Information Sharing Platform and Threat Sharing</title>
            <author>
              <organization>MISP Project</organization>
            </author>
            <date/>
          </front>
        </reference>
      </references>
    </references>

    <section anchor="acknowledgements" numbered="false" toc="default">
      <name>Acknowledgements</name>
      <t>The author thanks Frank Denis, Martin J. D&#xfc;rst, Ted Hardie, Graham Klyne, Eliot Lear, Barry Leiba, and Kathleen Moriarty for their review and feedback during the development of this document. The author also thanks the participants of the IETF SecDispatch and practical-cybersecurity discussions for early input on this work.</t>
    </section>

  </back>
</rfc>
