{"record":{"id":"7bf1c197779378c6","repo":"kestra-io/kestra","slug":"the-uri-is-not-in-the-configured-allowed-list","errorCode":null,"errorMessage":"The URI {} is not in the configured allowed list (kestra.tasks.http.allowed-list).","messagePattern":"The URI (.+?) is not in the configured allowed list \\(kestra\\.tasks\\.http\\.allowed-list\\)\\.","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/io/kestra/core/http/client/HttpClient.java","lineNumber":558,"sourceCode":"\n            if (e.getCause() instanceof HttpClientException httpClientException) {\n                throw httpClientException;\n            }\n\n            throw new RuntimeException(e);\n        }\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    private void validateUri(URI uri) {\n        String requestUri = uri.toString();\n        List<String> allowedList = (List<String>) ((DefaultRunContext) runContext).getTaskProperty(\"kestra.tasks.http.allowed-list\", List.class).orElse(Collections.emptyList());\n        List<String> deniedList = (List<String>) ((DefaultRunContext) runContext).getTaskProperty(\"kestra.tasks.http.denied-list\", List.class).orElse(Collections.emptyList());\n\n        // first check that if there is an allow list, it matches one\n        if (!allowedList.isEmpty()) {\n            if (allowedList.stream().noneMatch(requestUri::startsWith)) {\n                throw new IllegalArgumentException(\"The URI \" +  requestUri + \" is not in the configured allowed list (kestra.tasks.http.allowed-list).\");\n            }\n        }\n\n        // then check that there are no exclusion for it\n        if (deniedList.stream().anyMatch(requestUri::startsWith)) {\n            throw new IllegalArgumentException(\"The URI \" +  requestUri + \" is in the configured denied list (kestra.tasks.http.denied-list).\");\n        }\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    private <T> T bodyHandler(Class<?> cls, HttpEntity entity) throws IOException, ParseException {\n        if (entity == null) {\n            return null;\n        } else if (String.class.isAssignableFrom(cls)) {\n            return (T) EntityUtils.toString(entity);\n        } else if (Byte[].class.isAssignableFrom(cls)) {\n            return (T) ArrayUtils.toObject(EntityUtils.toByteArray(entity));\n        } else if (MediaType.APPLICATION_YAML.equals(entity.getContentType()) || \"application/yaml\".equals(entity.getContentType())) {","sourceCodeStart":540,"sourceCodeEnd":576,"githubUrl":"https://github.com/kestra-io/kestra/blob/823fada9274c4f9c251ea0a516460a4f7d958032/core/src/main/java/io/kestra/core/http/client/HttpClient.java#L540-L576","documentation":"Thrown by the Kestra HTTP client when an allow-list is configured (kestra.tasks.http.allowed-list) and the request URI does not start with any allowed prefix. validateUri reads the allowed-list task property; if non-empty and no entry matches requestUri.startsWith, it throws IllegalArgumentException naming the offending URI. This is a security control preventing SSRF.","triggerScenarios":"Task property kestra.tasks.http.allowed-list is a non-empty list; validateUri(request.uri) finds allowedList.stream().noneMatch(requestUri::startsWith); IllegalArgumentException is thrown.","commonSituations":"Allowed-list was tightened and the task targets a host not in it, the URI scheme changed (http vs https), a dynamic URI resolved to an unexpected host, or the allow-list prefix was typo'd.","solutions":["Add the request URI's scheme+host (and path prefix) to kestra.tasks.http.allowed-list.","Ensure the prefix match includes the scheme, e.g. 'https://api.example.com'.","If the URI is dynamic, constrain the expression so it only resolves to allowed hosts.","Review whether the allow-list should be relaxed or the task retargeted to an approved host."],"exampleFix":"# before\nkestra:\n  tasks:\n    http:\n      allowed-list:\n        - \"https://api.example.com/\"\n# task calls https://api.other.com -> rejected\n# after\nkestra:\n  tasks:\n    http:\n      allowed-list:\n        - \"https://api.example.com/\"\n        - \"https://api.other.com/\"","handlingStrategy":"validation","validationCode":"List<String> allowed = getTaskProperty('kestra.tasks.http.allowed-list', List.class).orElse(List.of());\nif (!allowed.isEmpty() && allowed.stream().noneMatch(uri.toString()::startsWith)) {\n  throw new IllegalStateException('URI not in allowed-list: ' + uri);\n}","typeGuard":null,"tryCatchPattern":"try {\n  validateUri(uri);\n} catch (IllegalArgumentException e) {\n  if (e.getMessage().contains('allowed list')) {\n    log.error('Allow-list rejected {}', uri);\n  }\n  throw e;\n}","preventionTips":["Maintain the allowed-list with full scheme+host prefixes.","Constrain dynamic URIs so they cannot leave the allow-list.","Review allow-list changes in security review."],"tags":["http-client","security","ssrf","allow-list","configuration"],"backgroundTag":null,"analyzedSha":"823fada9274c4f9c251ea0a516460a4f7d958032","analyzedAt":"2026-08-14T06:15:17.947Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}