This approach brought me much enlightenment
When <s:url includeParams=""/> is used, it takes existing params from HttpServletRequest. That class provides methods like getParameterMap() or getParameterValues() (among others). Those return parameters decoded. So no issue with them.
But as struts wants to explicitly handle GET parameters only it uses a different approach (in some cases): HttpServletRequest().getQueryString() (or: HttpServletRequest().getAttribute("javax.servlet.forward.query_string")). When paraters are accessed in this way they are not decoded.
Existing struts code is already prepared for that and does decoding for exactly these parameters. So it does already what I was about to add.
But here comes the other issue mentioned: URLDecoderUtil.decode() does not handle the + character for spaces.
So finally the decoding issue is the only issue.