diff --git a/bleach/sanitizer.py b/bleach/sanitizer.py
index 12225ef..faf8fd7 100644
--- a/bleach/sanitizer.py
+++ b/bleach/sanitizer.py
@@ -668,8 +668,20 @@ class BleachSanitizerFilter(sanitizer.Filter):
             assert token_type in ("StartTag", "EmptyTag")
             attrs = []
             for (ns, name), v in token["data"].items():
+                # If we end up with a namespace, but no name, switch them so we
+                # have a valid name to use.
+                if ns and not name:
+                    ns, name = name, ns
+
+                # Figure out namespaced name if the namespace is appropriate
+                # and exists; if the ns isn't in prefixes, then drop it.
+                if ns is None or ns not in prefixes:
+                    namespaced_name = name
+                else:
+                    namespaced_name = '%s:%s' % (prefixes[ns], name)
+
                 attrs.append(' %s="%s"' % (
-                    name if ns is None else "%s:%s" % (prefixes[ns], name),
+                    namespaced_name,
                     # NOTE(willkg): HTMLSerializer escapes attribute values
                     # already, so if we do it here (like HTMLSerializer does),
                     # then we end up double-escaping.

Exceptions on strange Html
Hello,

This small pattern raises an exception : 

    
    import bleach

    bleach.clean("<d {c}>")


diff --git a/tests/test_clean.py b/tests/test_clean.py
index 1f3cbfc..9547d63 100644
--- a/tests/test_clean.py
+++ b/tests/test_clean.py
@@ -759,6 +759,19 @@ def test_convert_entities(data, expected):
     assert convert_entities(data) == expected
 
 
+def test_nonexistent_namespace():
+    """Verify if the namespace doesn't exist, it doesn't fail with a KeyError
+
+    The tokenizer creates "c" as a namespace and that doesn't exist in the map
+    of namespaces, so then it fails with a KeyError. I don't understand why the
+    tokenizer makes "c" into a namespace in this string.
+
+    Issue #352.
+
+    """
+    assert clean('<d {c}>') == '&lt;d c=""&gt;&lt;/d&gt;'
+
+
 def get_tests():
     """Retrieves regression tests from data/ directory
 

pip install -e .[dev]
parse_log_pytest
requirements.txt
pytest
pip install -U pip setuptools>=18.5
3.9
requirements-dev.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
-e git+https://github.com/mozilla/bleach.git@a65f5c8ea664abbd54b4c711ebd0ca26c3509b7e#egg=bleach
exceptiongroup==1.2.2
html5lib==1.1
iniconfig==2.1.0
packaging==24.2
pluggy==1.5.0
pytest==8.3.5
six==1.17.0
tomli==2.2.1
webencodings==0.5.1

name: bleach
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=3.0.16=h5eee18b_0
  - python=3.9.21=he870216_1
  - readline=8.2=h5eee18b_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - tzdata=2025a=h04d1e81_0
  - wheel=0.45.1=py39h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - exceptiongroup==1.2.2
      - html5lib==1.1
      - iniconfig==2.1.0
      - packaging==24.2
      - pip==25.0.1
      - pluggy==1.5.0
      - pytest==8.3.5
      - setuptools==78.1.0
      - six==1.17.0
      - tomli==2.2.1
      - webencodings==0.5.1
prefix: /opt/conda/envs/bleach

tests/test_clean.py::test_nonexistent_namespace
tests/test_clean.py::test_uri_value_allowed_protocols[<a
tests/test_clean.py::test_clean_idempotent tests/test_clean.py::test_only_text_is_cleaned tests/test_clean.py::test_empty tests/test_clean.py::test_content_has_no_html tests/test_clean.py::test_content_has_allowed_html[an tests/test_clean.py::test_content_has_allowed_html[another tests/test_clean.py::test_html_is_lowercased tests/test_clean.py::test_comments[<!-- tests/test_clean.py::test_comments[<!--open tests/test_clean.py::test_comments[<!--comment-->text-True-text] tests/test_clean.py::test_comments[<!--comment-->text-False-<!--comment-->text] tests/test_clean.py::test_comments[text<!-- tests/test_clean.py::test_comments[text<!--comment-->-True-text] tests/test_clean.py::test_comments[text<!--comment-->-False-text<!--comment-->] tests/test_clean.py::test_disallowed_tags[<img tests/test_clean.py::test_disallowed_tags[a tests/test_clean.py::test_invalid_char_in_tag tests/test_clean.py::test_unclosed_tag tests/test_clean.py::test_nested_script_tag tests/test_clean.py::test_bare_entities_get_escaped_correctly[an tests/test_clean.py::test_bare_entities_get_escaped_correctly[tag tests/test_clean.py::test_character_entities_handling[&amp;-&amp;] tests/test_clean.py::test_character_entities_handling[&nbsp;-&nbsp;] tests/test_clean.py::test_character_entities_handling[&nbsp; tests/test_clean.py::test_character_entities_handling[&lt;em&gt;strong&lt;/em&gt;-&lt;em&gt;strong&lt;/em&gt;] tests/test_clean.py::test_character_entities_handling[&amp;is tests/test_clean.py::test_character_entities_handling[cool tests/test_clean.py::test_character_entities_handling[&&amp; tests/test_clean.py::test_character_entities_handling[&amp; tests/test_clean.py::test_character_entities_handling[this tests/test_clean.py::test_character_entities_handling[http://example.com?active=true&current=true-http://example.com?active=true&amp;current=true] tests/test_clean.py::test_character_entities_handling[<a tests/test_clean.py::test_character_entities_handling[&xx;-&xx;] tests/test_clean.py::test_character_entities_handling[&#39;-&#39;] tests/test_clean.py::test_character_entities_handling[&#34;-&#34;] tests/test_clean.py::test_character_entities_handling[&#123;-&#123;] tests/test_clean.py::test_character_entities_handling[&#x0007b;-&#x0007b;] tests/test_clean.py::test_character_entities_handling[&#x0007B;-&#x0007B;] tests/test_clean.py::test_character_entities_handling[&#-&amp;#] tests/test_clean.py::test_character_entities_handling[&#<-&amp;#&lt;] tests/test_clean.py::test_character_entities_handling[&#39;&#34;-&#39;&#34;] tests/test_clean.py::test_stripping_tags[a tests/test_clean.py::test_stripping_tags[<p><a tests/test_clean.py::test_stripping_tags[<p><span>multiply tests/test_clean.py::test_stripping_tags_is_safe[<scri<script>pt>alert(1)</scr</script>ipt>-pt&gt;alert(1)ipt&gt;] tests/test_clean.py::test_stripping_tags_is_safe[<scri<scri<script>pt>pt>alert(1)</script>-pt&gt;pt&gt;alert(1)] tests/test_clean.py::test_allowed_styles tests/test_clean.py::test_href_with_wrong_tag tests/test_clean.py::test_disallowed_attr tests/test_clean.py::test_unquoted_attr_values_are_quoted tests/test_clean.py::test_unquoted_event_handler_attr_value tests/test_clean.py::test_invalid_filter_attr tests/test_clean.py::test_poster_attribute tests/test_clean.py::test_attributes_callable tests/test_clean.py::test_attributes_wildcard tests/test_clean.py::test_attributes_wildcard_callable tests/test_clean.py::test_attributes_tag_callable tests/test_clean.py::test_attributes_tag_list tests/test_clean.py::test_attributes_list tests/test_clean.py::test_svg_attr_val_allows_ref tests/test_clean.py::test_svg_allow_local_href[<svg><pattern tests/test_clean.py::test_svg_allow_local_href_nonlocal[<svg><pattern tests/test_clean.py::test_weird_strings tests/test_clean.py::test_invisible_characters[1\x0723-1?23] tests/test_clean.py::test_invisible_characters[1\x0823-1?23] tests/test_clean.py::test_invisible_characters[1\x0b23-1?23] tests/test_clean.py::test_invisible_characters[1\x0c23-1?23] tests/test_clean.py::test_invisible_characters[import tests/test_clean.py::test_convert_entities[-] tests/test_clean.py::test_convert_entities[abc-abc] tests/test_clean.py::test_convert_entities[&nbsp;-\xa0] tests/test_clean.py::test_convert_entities[&#32;- tests/test_clean.py::test_convert_entities[&#x20;- tests/test_clean.py::test_convert_entities[&xx;-&xx;] tests/test_clean.py::test_regressions[/bleach/tests/data/1.test->"><script>alert("XSS")</script>&\n--\n&gt;"&gt;&lt;script&gt;alert("XSS")&lt;/script&gt;&amp;\n] tests/test_clean.py::test_regressions[/bleach/tests/data/2.test-"><STYLE>@import"javascript:alert('XSS')";</STYLE>\n--\n"&gt;&lt;style&gt;@import"javascript:alert('XSS')";&lt;/style&gt;\n] tests/test_clean.py::test_regressions[/bleach/tests/data/3.test->"'><img%20src%3D%26%23x6a;%26%23x61;%26%23x76;%26%23x61;%26%23x73;%26%23x63;%26%23x72;%26%23x69;%26%23x70;%26%23x74;%26%23x3a;alert(%26quot;%26%23x20;XSS%26%23x20;Test%26%23x20;Successful%26quot;)>\n--\n&gt;"'&gt;&lt;img%20src%3d%26%23x6a;%26%23x61;%26%23x76;%26%23x61;%26%23x73;%26%23x63;%26%23x72;%26%23x69;%26%23x70;%26%23x74;%26%23x3a;alert(%26quot;%26%23x20;xss%26%23x20;test%26%23x20;successful%26quot;)&gt;&lt;/img%20src%3d%26%23x6a;%26%23x61;%26%23x76;%26%23x61;%26%23x73;%26%23x63;%26%23x72;%26%23x69;%26%23x70;%26%23x74;%26%23x3a;alert(%26quot;%26%23x20;xss%26%23x20;test%26%23x20;successful%26quot;)&gt;\n] tests/test_clean.py::test_regressions[/bleach/tests/data/4.test-<scr<script></script>ipt tests/test_clean.py::test_regressions[/bleach/tests/data/5.test->%22%27><img%20src%3d%22javascript:alert(%27%20XSS%27)%22>\n--\n&gt;%22%27&gt;&lt;img%20src%3d%22javascript:alert(%27%20xss%27)%22&gt;&lt;/img%20src%3d%22javascript:alert(%27%20xss%27)%22&gt;\n] tests/test_clean.py::test_regressions[/bleach/tests/data/6.test-<a tests/test_clean.py::test_regressions[/bleach/tests/data/7.test-">\n--\n"&gt;\n] tests/test_clean.py::test_regressions[/bleach/tests/data/8.test->"\n--\n&gt;"\n] tests/test_clean.py::test_regressions[/bleach/tests/data/9.test-'';!--"<XSS>=&{()}\n--\n'';!--"&lt;xss&gt;=&amp;{()}&lt;/xss&gt;\n] tests/test_clean.py::test_regressions[/bleach/tests/data/10.test-<IMG tests/test_clean.py::test_regressions[/bleach/tests/data/11.test-<IMG tests/test_clean.py::test_regressions[/bleach/tests/data/12.test-<IMG tests/test_clean.py::test_regressions[/bleach/tests/data/13.test-<IMG tests/test_clean.py::test_regressions[/bleach/tests/data/14.test-<IMGSRC=&#106;&#97;&#118;&#97;&<WBR>#115;&#99;&#114;&#105;&#112;&<WBR>#116;&#58;&#97;\n--\n&lt;imgsrc=&amp;#106;&amp;#97;&amp;#118;&amp;#97;&amp;&lt;wbr&gt;#115;&#99;&#114;&#105;&#112;&amp;&lt;wbr&gt;&lt;/wbr&gt;#116;&#58;&#97;&lt;/imgsrc=&amp;#106;&amp;#97;&amp;#118;&amp;#97;&amp;&lt;wbr&gt;\n] tests/test_clean.py::test_regressions[/bleach/tests/data/15.test-&#108;&#101;&<WBR>#114;&#116;&#40;&#39;&#88;&#83<WBR>;&#83;&#39;&#41>\n--\n&#108;&#101;&amp;&lt;wbr&gt;&lt;/wbr&gt;#114;&#116;&#40;&#39;&#88;&amp;#83&lt;wbr&gt;&lt;/wbr&gt;;&#83;&#39;&amp;#41&gt;\n] tests/test_clean.py::test_regressions[/bleach/tests/data/16.test-<IMGSRC=&#0000106&#0000097&<WBR>#0000118&#0000097&#0000115&<WBR>#0000099&#0000114&#0000105&<WBR>#0000112&#0000116&#0000058&<WBR>#0000097&#0000108&#0000101&<WBR>#0000114&#0000116&#0000040&<WBR>#0000039&#0000088&#0000083&<WBR>#0000083&#0000039&#0000041>\n--\n&lt;imgsrc=&amp;#0000106&amp;#0000097&amp;&lt;wbr&gt;#0000118&amp;#0000097&amp;#0000115&amp;&lt;wbr&gt;&lt;/wbr&gt;#0000099&amp;#0000114&amp;#0000105&amp;&lt;wbr&gt;&lt;/wbr&gt;#0000112&amp;#0000116&amp;#0000058&amp;&lt;wbr&gt;&lt;/wbr&gt;#0000097&amp;#0000108&amp;#0000101&amp;&lt;wbr&gt;&lt;/wbr&gt;#0000114&amp;#0000116&amp;#0000040&amp;&lt;wbr&gt;&lt;/wbr&gt;#0000039&amp;#0000088&amp;#0000083&amp;&lt;wbr&gt;&lt;/wbr&gt;#0000083&amp;#0000039&amp;#0000041&gt;&lt;/imgsrc=&amp;#0000106&amp;#0000097&amp;&lt;wbr&gt;\n] tests/test_clean.py::test_regressions[/bleach/tests/data/17.test-<IMGSRC=&#x6A&#x61&#x76&#x61&#x73&<WBR>#x63&#x72&#x69&#x70&#x74&#x3A&<WBR>#x61&#x6C&#x65&#x72&#x74&#x28&<WBR>#x27&#x58&#x53&#x53&#x27&#x29>\n--\n&lt;imgsrc=&amp;#x6a&amp;#x61&amp;#x76&amp;#x61&amp;#x73&amp;&lt;wbr&gt;#x63&amp;#x72&amp;#x69&amp;#x70&amp;#x74&amp;#x3A&amp;&lt;wbr&gt;&lt;/wbr&gt;#x61&amp;#x6C&amp;#x65&amp;#x72&amp;#x74&amp;#x28&amp;&lt;wbr&gt;&lt;/wbr&gt;#x27&amp;#x58&amp;#x53&amp;#x53&amp;#x27&amp;#x29&gt;&lt;/imgsrc=&amp;#x6a&amp;#x61&amp;#x76&amp;#x61&amp;#x73&amp;&lt;wbr&gt;\n] tests/test_clean.py::test_regressions[/bleach/tests/data/18.test-<IMG tests/test_clean.py::test_regressions[/bleach/tests/data/19.test-<IMG tests/test_clean.py::test_regressions[/bleach/tests/data/20.test-<IMG tests/test_clean.py::TestCleaner::test_basics tests/test_clean.py::TestCleaner::test_filters
bleach/sanitizer.py
bleach/sanitizer.py