You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Website applications often need to respond to a requested action based on input provided by a user. If that response contains a copy of the user’s input without proper neutralization, then a dangerous attack known as Cross-Site Scripting (XSS) may be possible. The underlying weakness that leads to XSS is annually one of the CWE™ Top 25 Most Dangerous Software Weaknesses, ranking at #2 in 2023 and #1 in 2024. In 2023, such a weakness was discovered in Miniflux, a web feed reader. This case study will examine the weakness, the resulting vulnerability, what it allowed an adversary to accomplish, and how the issue was eventually mitigated.
6
6
7
-
###Software:
7
+
## Software
8
8
9
9
**Name:** Miniflux
10
10
**Language:** Go
11
-
**URL:**https://github.com/miniflux/v2
11
+
**URL:**<https://github.com/miniflux/v2>
12
12
13
-
###Weakness:
13
+
## Weakness
14
14
15
-
<ahref="https://cwe.mitre.org/data/definitions/79.html">CWE-79: Improper Neutralization of Input During Web Page Generation</a>
15
+
[CWE-79: Improper Neutralization of Input During Web Page Generation](https://cwe.mitre.org/data/definitions/79.html)
16
16
17
17
The weakness exists when a web application fails to properly neutralize user-controlled input in the web application's code, and the input is then used as part of a response to a user's request.
18
18
19
19
There are three main kinds of cross-site scripting (XSS): reflected, stored, and DOM-based. This case study will focus on stored XSS, which is when a web application reads potentially dangerous input that was stored in a server-side location. This dangerous input is then read back into the application at some future time and included in a response that is sent back to the user. For example, an attacker could leave a comment on a forum that contains a malicious script. This comment is stored in the forum's back-end database, and then retreived anytime a user views the forum page.
20
20
21
-
###Vulnerability:
21
+
## Vulnerability
22
22
23
-
<ahref="https://www.cve.org/CVERecord?id=CVE-2023-27592">CVE-2023-27592</a> - Published 17 March 2023
23
+
[CVE-2023-27592](https://www.cve.org/CVERecord?id=CVE-2023-27592) - Published 17 March 2023
24
24
25
25
Miniflux is a feed reader that supports Really Simple Syndication (RSS). Subscribing to an RSS feed can allow users to keep up to date on many different websites in a central hub without having to check each website manually. An RSS feed item is a single entry in the RSS feed that corresponds to an update from a website the feed is pulling from. Miniflux displays RSS feed items from a user's RSS subcscriptions in a central hub for users to view.
26
26
@@ -36,36 +36,40 @@ A CSP is a set of instructions that a web browser follows to restrict actions th
36
36
37
37
Looking at the proxy.go code, the vulnerable section begins at line 85 which is triggered if the Miniflux server encounters an error while processing the request. On line 86, the Miniflux server sends an HTTP Internal Server Error response to the user by calling the function html.ServerError, which includes an addition to the error log and builds the entry that will be added to the user's Miniflux inbox.
38
38
39
-
vulnerable file: miniflux/v2/internal/ui/proxy.go
40
-
41
-
23 func (h *handler) mediaProxy(w http.ResponseWriter, r *http.Request) {
42
-
...
43
-
85 if err != nil {
44
-
86 html.ServerError(w, r, err)
45
-
87 return
46
-
88 }
47
-
...
48
-
118 }
39
+
```
40
+
vulnerable file: miniflux/v2/internal/ui/proxy.go
41
+
42
+
23 func (h *handler) mediaProxy(w http.ResponseWriter, r *http.Request) {
43
+
...
44
+
85 if err != nil {
45
+
86 html.ServerError(w, r, err)
46
+
87 return
47
+
88 }
48
+
...
49
+
118 }
50
+
```
49
51
50
52
Note that the ServerError function in html.go does not add a CSP header to the Miniflux entry that is built. As a result, when the mediaProxy function returns on line 87 above, the entry that is added to the user's Miniflux inbox has no restrictions on what JavaScript can be embedded in any media (like an image) within the RSS feed item, despite the user seeing an HTTP 500 Iternal Server Error.
To exploit this vulnerability, an adversary starts by convincing a user to subscribe to an adversary-controlled RSS feed via Miniflux. Then, the adversary can craft an item for this RSS feed that contains an inline description with an <img> tag and a srcset attribute that uses an invalid URL that contains malicious JavaScript. An example RSS feed item is provided below.
71
75
@@ -85,69 +89,78 @@ To exploit this vulnerability, an adversary starts by convincing a user to subsc
85
89
86
90
Notice the JavaScript contained in the srcset attribute. If the Miniflux user is subscribed to the adversary's RSS feed, the code in the mediaProxy function will reach the vulnerable section and add this RSS feed item to the user's Miniflux inbox. When the web browser loads the broken image, the malicious JavaScript is executed in the context of the victim Miniflux user. Actions will be performed on the Miniflux instance as the victim. If the victim is an administrator, administrative access to the Miniflux instance can be achieved. Actions that can be taken include but are not limited to the manipulation or theft of site cookies, a compromise of confidential information, the disclosure of end user files, the installation of Trojan horse programs, or redirection of the user to another site.
87
91
88
-
###Fix:
92
+
## Fix
89
93
90
94
To resolve this issue the source code was modified to remove the call to html.ServerError and thus prevent the Miniflux inbox entry from being built, replacing it with a logger error and an HTTP error on lines 86 and 87.
91
95
92
-
fixed file: miniflux/v2/internal/ui/proxy.go
93
-
94
-
23 func (h *handler) mediaProxy(w http.ResponseWriter, r *http.Request) {
95
-
...
96
-
85 if err != nil {
97
-
86 logger.Error(`[Proxy] Unable to initialize HTTP client: %v`, err)
Now, the mediaProxy function does not build a Miniflux inbox entry like the earlier example and will instead simply log an error which avoids adding an RSS feed item to the user's inbox when this section of code is executed.
105
112
106
113
Additionally, a CSP was added to the header on line 29 of html.go to any Miniflux inbox entries that are built when ServerError is called. The CSP sets the default-src to 'self', which means that the browser will only load resources (like images) that originate from Miniflux.
Now, even if a Miniflux inbox entry is built with an error response, a CSP will be utilized to defend against XSS attacks.
124
133
125
-
### Conclusion:
134
+
## Prevention
135
+
136
+
To prevent future issues like this take care when generating error messages and make sure that user provided data is not included within the mesage.
137
+
138
+
## Conclusion
126
139
127
140
Improper neutralization of input is a common weakness that annually ranks among the CWE™ Top 25 Most Dangerous Software Weaknesses, ranking #2 in 2023 and #1 in 2024. The weakness can lead to remote code execution and/or the reading of application data. One such weakness led to a vulnerability that was discovered in Miniflux in 2023. In response, Miniflux made changes to ensure that unneutralized input was not added to a user's RSS feed. Instead, an error would be logged, effectively mitigating the root weakness of “Improper Neutralization of Input During Web Page Generation”. Without this weakness, Miniflux can no longer be exploited in a stored XSS attack to execute JavaScript code on the Miniflux instance. Software developers should always follow secure coding practices and ensure any user-controlled input is effectively neutralized to avoid such vulnerabilities in their own projects.
0 commit comments