2d7c13
diff --git a/src/lxml/html/defs.py b/src/lxml/html/defs.py
2d7c13
index caf6b21..ea3c016 100644
2d7c13
--- a/src/lxml/html/defs.py
2d7c13
+++ b/src/lxml/html/defs.py
2d7c13
@@ -21,6 +21,8 @@ link_attrs = frozenset([
2d7c13
     'usemap',
2d7c13
     # Not standard:
2d7c13
     'dynsrc', 'lowsrc',
2d7c13
+    # HTML5 formaction
2d7c13
+    'formaction'
2d7c13
     ])
2d7c13
 
2d7c13
 # Not in the HTML 4 spec:
2d7c13
diff --git a/src/lxml/html/tests/test_clean.py b/src/lxml/html/tests/test_clean.py
2d7c13
index 451eec2..e40cdad 100644
2d7c13
--- a/src/lxml/html/tests/test_clean.py
2d7c13
+++ b/src/lxml/html/tests/test_clean.py
2d7c13
@@ -89,6 +89,21 @@ class CleanerTest(unittest.TestCase):
2d7c13
             b'<math><style>/* deleted */</style></math>',
2d7c13
             lxml.html.tostring(clean_html(s)))
2d7c13
 
2d7c13
+    def test_formaction_attribute_in_button_input(self):
2d7c13
+        # The formaction attribute overrides the form's action and should be
2d7c13
+        # treated as a malicious link attribute
2d7c13
+        html = ('<form id="test"><input type="submit" formaction="javascript:alert(1)"></form>'
2d7c13
+        '<button form="test" formaction="javascript:alert(1)">X</button>')
2d7c13
+        expected = ('
<form id="test"><input type="submit" formaction=""></form>'
2d7c13
+        '<button form="test" formaction="">X</button>')
2d7c13
+        cleaner = Cleaner(
2d7c13
+            forms=False,
2d7c13
+            safe_attrs_only=False,
2d7c13
+        )
2d7c13
+        self.assertEqual(
2d7c13
+            expected,
2d7c13
+            cleaner.clean_html(html))
2d7c13
+
2d7c13
 
2d7c13
 def test_suite():
2d7c13
     suite = unittest.TestSuite()