fix(security): disable reading config params from URL search params (#7697)
Reading configuration parameters from URL search params is by default no longer enabled. To re-enable it, set queryConfigEnabled configuration parameter to true. Functionally, this is a breaking change, but given we're just providing a security vulnerability patch we're considering this a PATCH version bump only. Refs #4872 Refs https://github.com/swagger-api/swagger-ui/security/advisories/GHSA-qrmm-w75w-3wpx
This commit is contained in:
@@ -43,6 +43,13 @@ const defaultBaseConfig = {
|
||||
type: "string",
|
||||
base: true
|
||||
}
|
||||
},
|
||||
queryConfigEnabled: {
|
||||
value: "false",
|
||||
schema: {
|
||||
type: "boolean",
|
||||
base: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,14 +58,14 @@ function objectToKeyValueString(env, { injectBaseConfig = false, schema = config
|
||||
const keys = Object.keys(env)
|
||||
|
||||
// Compute an intermediate representation that holds candidate values and schemas.
|
||||
//
|
||||
//
|
||||
// This is useful for deduping between multiple env keys that set the same
|
||||
// config variable.
|
||||
|
||||
keys.forEach(key => {
|
||||
const varSchema = schema[key]
|
||||
const value = env[key]
|
||||
|
||||
|
||||
if(!varSchema) return
|
||||
|
||||
if(varSchema.onFound) {
|
||||
@@ -88,8 +95,8 @@ function objectToKeyValueString(env, { injectBaseConfig = false, schema = config
|
||||
|
||||
Object.keys(valueStorage).forEach(key => {
|
||||
const value = valueStorage[key]
|
||||
|
||||
const escapedName = /[^a-zA-Z0-9]/.test(key) ? `"${key}"` : key
|
||||
|
||||
const escapedName = /[^a-zA-Z0-9]/.test(key) ? `"${key}"` : key
|
||||
|
||||
if (value.schema.type === "string") {
|
||||
result += `${escapedName}: "${value.value}",\n`
|
||||
@@ -101,4 +108,4 @@ function objectToKeyValueString(env, { injectBaseConfig = false, schema = config
|
||||
return result.trim()
|
||||
}
|
||||
|
||||
module.exports = objectToKeyValueString
|
||||
module.exports = objectToKeyValueString
|
||||
|
||||
@@ -23,6 +23,10 @@ const standardVariables = {
|
||||
type: "string",
|
||||
name: "urls.primaryName"
|
||||
},
|
||||
QUERY_CONFIG_ENABLED: {
|
||||
type: "boolean",
|
||||
name: "queryConfigEnabled"
|
||||
},
|
||||
LAYOUT: {
|
||||
type: "string",
|
||||
name: "layout"
|
||||
|
||||
@@ -31,6 +31,7 @@ Parameter name | Docker variable | Description
|
||||
<a name="url"></a>`url` | `URL` | `String`. The URL pointing to API definition (normally `swagger.json` or `swagger.yaml`). Will be ignored if `urls` or `spec` is used.
|
||||
<a name="urls"></a>`urls` | `URLS` | `Array`. An array of API definition objects (`[{url: "<url1>", name: "<name1>"},{url: "<url2>", name: "<name2>"}]`) used by Topbar plugin. When used and Topbar plugin is enabled, the `url` parameter will not be parsed. Names and URLs must be unique among all items in this array, since they're used as identifiers.
|
||||
<a name="urls.primaryName"></a>`urls.primaryName` | `URLS_PRIMARY_NAME` | `String`. When using `urls`, you can use this subparameter. If the value matches the name of a spec provided in `urls`, that spec will be displayed when Swagger UI loads, instead of defaulting to the first spec in `urls`.
|
||||
<a name="queryConfigEnabled"></a>`queryConfigEnabled` | `QUERY_CONFIG_ENABLED` | `Boolean=false`. Enables overriding configuration parameters via URL search params.
|
||||
|
||||
##### Plugin system
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ export default class SwaggerUI extends React.Component {
|
||||
onComplete: this.onComplete,
|
||||
docExpansion: this.props.docExpansion,
|
||||
supportedSubmitMethods: this.props.supportedSubmitMethods,
|
||||
queryConfigEnabled: this.props.queryConfigEnabled,
|
||||
defaultModelExpandDepth: this.props.defaultModelExpandDepth,
|
||||
displayOperationId: this.props.displayOperationId,
|
||||
tryItOutEnabled: this.props.tryItOutEnabled,
|
||||
@@ -29,7 +30,7 @@ export default class SwaggerUI extends React.Component {
|
||||
showMutatedRequest: typeof this.props.showMutatedRequest === "boolean" ? this.props.showMutatedRequest : true,
|
||||
deepLinking: typeof this.props.deepLinking === "boolean" ? this.props.deepLinking : false,
|
||||
showExtensions: this.props.showExtensions,
|
||||
filter: ["boolean", "string"].includes(typeof this.props.filter) ? this.props.filter : false,
|
||||
filter: ["boolean", "string"].includes(typeof this.props.filter) ? this.props.filter : false,
|
||||
})
|
||||
|
||||
this.system = ui
|
||||
@@ -99,6 +100,7 @@ SwaggerUI.propTypes = {
|
||||
supportedSubmitMethods: PropTypes.arrayOf(
|
||||
PropTypes.oneOf(["get", "put", "post", "delete", "options", "head", "patch", "trace"])
|
||||
),
|
||||
queryConfigEnabled: PropTypes.bool,
|
||||
plugins: PropTypes.arrayOf(PropTypes.object),
|
||||
displayOperationId: PropTypes.bool,
|
||||
showMutatedRequest: PropTypes.bool,
|
||||
@@ -119,6 +121,7 @@ SwaggerUI.propTypes = {
|
||||
SwaggerUI.defaultProps = {
|
||||
layout: "BaseLayout",
|
||||
supportedSubmitMethods: ["get", "put", "post", "delete", "options", "head", "patch", "trace"],
|
||||
queryConfigEnabled: false,
|
||||
docExpansion: "list",
|
||||
defaultModelsExpandDepth: 1,
|
||||
presets: [],
|
||||
|
||||
@@ -77,6 +77,7 @@ export default function SwaggerUI(opts) {
|
||||
"patch",
|
||||
"trace"
|
||||
],
|
||||
queryConfigEnabled: false,
|
||||
|
||||
// Initial set of plugins ( TODO rename this, or refactor - we don't need presets _and_ plugins. Its just there for performance.
|
||||
// Instead, we can compile the first plugin ( it can be a collection of plugins ), then batch the rest.
|
||||
@@ -108,7 +109,7 @@ export default function SwaggerUI(opts) {
|
||||
}
|
||||
}
|
||||
|
||||
let queryConfig = parseSearch()
|
||||
let queryConfig = opts.queryConfigEnabled ? parseSearch() : {}
|
||||
|
||||
const domNode = opts.domNode
|
||||
delete opts.domNode
|
||||
|
||||
@@ -56,7 +56,8 @@
|
||||
} else {
|
||||
window.completeCount = 1
|
||||
}
|
||||
}
|
||||
},
|
||||
queryConfigEnabled: true,
|
||||
})
|
||||
|
||||
window.ui = ui
|
||||
|
||||
@@ -65,7 +65,8 @@
|
||||
} else {
|
||||
window.completeCount = 1
|
||||
}
|
||||
}
|
||||
},
|
||||
queryConfigEnabled: true,
|
||||
})
|
||||
|
||||
window.ui = ui
|
||||
|
||||
@@ -109,6 +109,7 @@ describe("docker: env translator", function() {
|
||||
SwaggerUIBundle.plugins.DownloadUrl
|
||||
],
|
||||
layout: "StandaloneLayout",
|
||||
queryConfigEnabled: false,
|
||||
`))
|
||||
})
|
||||
|
||||
@@ -214,6 +215,7 @@ describe("docker: env translator", function() {
|
||||
SwaggerUIBundle.plugins.DownloadUrl
|
||||
],
|
||||
layout: "StandaloneLayout",
|
||||
queryConfigEnabled: false,
|
||||
url: "/swagger.json",
|
||||
urls: ["/one", "/two"],`
|
||||
|
||||
@@ -313,6 +315,7 @@ describe("docker: env translator", function() {
|
||||
plugins: [
|
||||
SwaggerUIBundle.plugins.DownloadUrl
|
||||
],
|
||||
queryConfigEnabled: false,
|
||||
configUrl: "/wow",
|
||||
"dom_id": "#swagger_ui",
|
||||
spec: { swagger: "2.0" },
|
||||
|
||||
Reference in New Issue
Block a user