{"id":47444108,"url":"https://github.com/charlieIT/ContentSecurityPolicy.jl","last_synced_at":"2026-04-06T13:00:57.591Z","repository":{"id":142456098,"uuid":"472450082","full_name":"charlieIT/ContentSecurityPolicy.jl","owner":"charlieIT","description":"Julia library for working with Content Security Policy","archived":false,"fork":false,"pushed_at":"2023-03-17T14:43:39.000Z","size":68,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-09-23T09:57:00.325Z","etag":null,"topics":["content-security-policy","content-security-policy-report","csp","julia","middleware","secure-headers","security","web","web-security","xss"],"latest_commit_sha":null,"homepage":"","language":"Julia","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/charlieIT.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2022-03-21T17:50:43.000Z","updated_at":"2023-11-19T00:50:14.000Z","dependencies_parsed_at":null,"dependency_job_id":"336e475e-f98a-461e-94d6-6ee14eefba6e","html_url":"https://github.com/charlieIT/ContentSecurityPolicy.jl","commit_stats":{"total_commits":35,"total_committers":3,"mean_commits":"11.666666666666666","dds":0.4571428571428572,"last_synced_commit":"e67e902a42166c2ae376359657c18891105b2af1"},"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/charlieIT/ContentSecurityPolicy.jl","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/charlieIT%2FContentSecurityPolicy.jl","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/charlieIT%2FContentSecurityPolicy.jl/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/charlieIT%2FContentSecurityPolicy.jl/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/charlieIT%2FContentSecurityPolicy.jl/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/charlieIT","download_url":"https://codeload.github.com/charlieIT/ContentSecurityPolicy.jl/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/charlieIT%2FContentSecurityPolicy.jl/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31473271,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-06T08:36:52.050Z","status":"ssl_error","status_checked_at":"2026-04-06T08:36:51.267Z","response_time":112,"last_error":"SSL_read: 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":["content-security-policy","content-security-policy-report","csp","julia","middleware","secure-headers","security","web","web-security","xss"],"created_at":"2026-03-23T06:00:59.902Z","updated_at":"2026-04-06T13:00:57.578Z","avatar_url":"https://github.com/charlieIT.png","language":"Julia","funding_links":[],"categories":["Web Security"],"sub_categories":["Content Security"],"readme":"# ContentSecurityPolicy\n\nA Julia library to aid the integration of **[Content-Security-Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP)** headers into web applications.\n\n**References** \n- [MDN CSP](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP)\n- [OWASP CSP](https://cheatsheetseries.owasp.org/cheatsheets/Content_Security_Policy_Cheat_Sheet.html)\n- [Strict CSP](https://web.dev/strict-csp/#what-is-a-strict-content-security-policy)\n- [W3C CSP3](https://www.w3.org/TR/CSP3/)\n- [csp.withgoogle](https://csp.withgoogle.com/docs/index.html)\n- [CSP cheatsheet](https://scotthelme.co.uk/csp-cheat-sheet/)\n- [CSP-Builder](https://github.com/paragonie/csp-builder)\n- [django-csp](https://django-csp.readthedocs.io/en/latest/)\n\n## Project status\n\nThe package is under active development and changes may occur.\n\n### ToDo\n\n- [x] Register package\n- [ ] Improve support for csp-nonce and csp-hash\n- [ ] Improve default strict policy and improve overall configurability\n- [ ] Handle CSP violation reports\n- [ ] Export nginx and Apache header configurations\n\n## Contributions, suggestions, questions\n\nAll are welcome, as well as feature requests and bug reports. Please open an issue, discussion topic or submit a PR.\n\n## Table of Contents\n\n1. [Installation](#installation)\n2. [Usage examples](#usage-examples)\n3. [Web example](#web-example)\n4. [Import from JSON](#policy-from-a-json-file)\n5. [API Reference](#api-reference)\n\n## Installation\n\nThe package can be installed via package manager\n```julia\npkg\u003e add ContentSecurityPolicy\n```\n\nIt can also be installed by providing a [URL to the repository](https://pkgdocs.julialang.org/v1/managing-packages/#Adding-unregistered-packages)\n```julia\npkg\u003e add https://github.com/charlieIT/ContentSecurityPolicy.jl\n```\n\n## Usage examples\n\n```julia\nusing ContentSecurityPolicy\n```\n\nCan be used as `CSP`, for name shortening purposes\n```julia\nusing ContentSecurityPolicy\nCSP.Policy()\n```\n\n### Build a Content Security Policy\n```julia\nPolicy(\n   # Set fallback for all fetch directives\n    \"default-src\"=\u003e\"*\",\n    # Set valid sources of images and favicons\n    \"img-src\"=\u003e(\"'self'\", \"data:\"),\n    # Turn on https enforcement\n    \"upgrade-insecure-requests\"=\u003etrue,\n    # Custom directives are supported, if needed\n    \"some-custom-directive\"=\u003e[\"foo\", \"bar\"]\n)\n```\n\u003cdetails\u003e\n\u003csummary\u003eOutput\u003c/summary\u003e\n\n```json\n{\n    \"default-src\": \"*\",\n    \"img-src\": [\n        \"'self'\",\n        \"data:\"\n    ],\n    \"upgrade-insecure-requests\": true,\n    \"some-custom-directive\": [\n        \"foo\",\n        \"bar\"\n    ],\n    \"report-only\": false\n}\n```\n\u003c/details\u003e\n\nSee also: [Policy](#policy), [Strict Policy](#strict-policy).\n\n### Edit existing policy\n\nModify multiple directives at once\n```julia\n# Modify multiple directives at once\npolicy(\n    # Pairs before kwargs\n    \"script-src\" =\u003e (\"'unsafe-inline'\", \"http://example.com\"),\n    img_src = (\"'self'\", \"data:\")\n)\n```\nModify single directive\n```julia\n# Modify individually via directive name\npolicy[\"img-src\"] = CSP.wildcard # \"*\"\n```\n\n### Build `http` headers\n\n**Content-Security-Policy** header\n```julia\nusing ContentSecurityPolicy, HTTP\n\nHTTP.Header(Policy(default=true))\n```\n```julia\n\"Content-Security-Policy\" =\u003e \"base-uri none; default-src 'self'; frame-ancestors none; object-src none; report-to default; script-src 'strict-dynamic'\"\n```\n**Report-Only** header\n```julia\npolicy = Policy(\n        \"default-src\"=\u003eCSP.self,\n        \"report-to\"=\u003e\"some-endpoint\",\n        report_only=true)\n        \nHTTP.Header(policy)\n```\n```julia\n\"Content-Security-Policy-Report-Only\" =\u003e \"default-src 'self'; report-to some-endpoint\"\n```\n\n### Build `\u003cmeta\u003e` element\n\nConstruction will automatically ignore directives that are not supported in the `\u003cmeta\u003e` element. Currently `[frame-ancestors, report-uri, report-to, sandbox]`. \n\nSee also [mdn csp directives](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP).\n```julia\nCSP.meta(Policy(report_to=\"default\", default_src=\"'self'\"))\n```\n```xml\n\u003cmeta http-equiv=\"Content-Security-Policy\" content=\"default-src 'self'\"\u003e\n```\n\n### Obtain CSP header as Dict\n```julia\npolicy = csp(\"default-src\"=\u003eCSP.self, \"img-src\"=\u003e(CSP.self, CSP.data), \"report-uri\"=\u003e\"/api/reports\")\n\nCSP.http(policy)\n```\n\u003cdetails\u003e\n\u003csummary\u003eOutput\u003c/summary\u003e\n\n```\nOrderedCollections.OrderedDict{String, Any} with 3 entries:\n  \"img-src\"     =\u003e \"data: 'self'\"\n  \"default-src\" =\u003e \"'self'\"\n  \"report-uri\"  =\u003e \"/api/reports\"\n```\n\u003c/details\u003e\n\n## Web example\n\n**Mockup** web application with dynamic CSP policies, that can also receive CSP violation reports.\n\nThe example app will allow route handlers to tailor the CSP Policy on each response.\n```julia\nusing ContentSecurityPolicy, Dates, HTTP, JSON3, Random, Sockets\n```\n**Middleware for adding CSP header to each response**\n```julia\n\"\"\"\nA middleware that will set a restrictive default policy.\n\nAllows route handlers to change the CSP Policy\n\"\"\"\nfunction CSPMiddleware(next)\n    return function(request::HTTP.Request)\n\n        function respond(response::HTTP.Response)\n            timestamp = string(round(Int, datetime2unix(now())))\n                \n            # A default restrictive policy\n            policy = csp(\n                default = true, \n                default_src = \"'self'\", \n                script_src = \"none\",\n                report_to = false,\n                sandbox = true, \n                report_uri = \"/reports/$timestamp\") # report to specific endpoint\n\n            if !isnothing(request.context)\n                if haskey(request.context, :csp)\n                    # Acquire the policy defined by the route and log\n                    route_policy = request.context[:csp]\n                    @info \"Custom policy: $(string(route_policy))\"\n\n                    # Merge default with handler provided policy\n                    policy = policy(route_policy.directives...)\n                end \n            end\n            # Check whether header was not yet defined\n            if !HTTP.hasheader(response, CSP.CSP_HEADER)\n                # Set CSP policy header\n                HTTP.setheader(response, HTTP.Header(policy))\n            end\n            return response\n        end\n\treturn respond(next(request))\n    end\nend\n```\n**Handler for posted csp violation reports**\n```julia\n\"\"\"\nHandle posted CSP Reports\n\"\"\"\nfunction report(request::HTTP.Request)\n    report = String(request.body)\n    # Each report is posted to /reports/{timestamp}\n    timestamp = Base.parse(Int, request.context[:params][\"timestamp\"])\n    # Log timestamp as Date\n    println(string(\"Timestamp: \", unix2datetime(timestamp)))\n    # Log pretty json report\n    JSON3.pretty(report)\n\n    return HTTP.Response(200, report)\nend\n```\n**A page with restrictive csp policy**\n```julia\nfunction restrictive(request::HTTP.Request)\n    # Obtain a nonce\n    nonce = CSP.csp_nonce()\n    # Set a policy allowing scripts with our nonce, also enabling scripts and modals in sandbox mode\n    request.context[:csp] = csp(script_src=\"'nonce-$nonce'\", sandbox=\"allow-scripts allow-modals\")\n\n    html = \"\"\"\n    \u003chtml\u003e\n        \u003cbody\u003e\n            \u003c!-- This will execute --\u003e\n            \u003cscript type=\"text/javascript\", nonce='$nonce'\u003e\n                alert('I can execute!');\n            \u003c/script\u003e\n            \n            \u003c!-- This should not execute --\u003e\n            \u003cscript type=\"text/javascript\"\u003e\n                alert('Not authorised!');\n            \u003c/script\u003e\n        \u003c/body\u003e\n    \u003c/html\u003e\n    \"\"\"\n    return HTTP.Response(200, html)\nend\n```\n**A page with a more permissive csp policy**\n```julia\nfunction permissive(request::HTTP.Request)\n    # Set permissive script-src to allow all inline scripts\n    request.context[:csp] = csp(\"script-src\"=\u003e(\"'self'\", \"'unsafe-inline'\"), \"sandbox\"=\u003efalse)\n\n    html = \"\"\"\n    \u003chtml\u003e\n        \u003cbody\u003e\n            \u003cdiv id=\"hello\"\u003e\u003c/div\u003e\n            \u003cscript type=\"text/javascript\"\u003e\n                document.getElementById('hello').innerHTML = 'Scripts can execute!';\n            \u003c/script\u003e\n            \u003cscript type=\"text/javascript\"\u003e\n                alert('Scripts can launch modals!');\n            \u003c/script\u003e\n        \u003c/body\u003e\n    \u003c/html\u003e\n    \"\"\"\n    return HTTP.Response(200, html)\nend\n```\n**Setup http routing**\n```julia\nconst csp_router = HTTP.Router()\nHTTP.register!(csp_router, \"GET\", \"/restrictive\", restrictive)\nHTTP.register!(csp_router, \"GET\", \"/permissive\", permissive)\n# Handle incoming CSP reports\nHTTP.register!(csp_router, \"POST\", \"/reports/{timestamp}\", report)\n\nserver = HTTP.serve!(csp_router |\u003e CSPMiddleware, ip\"0.0.0.0\", 80)\n```\nSee also: [web example](/examples/web).\n\n## Policy from a JSON file\n\n[Example configuration.json](/examples/conf.json)\n\n```julia\npolicy = Policy(\"/path/to/conf.json\")\n```\n```julia\npolicy[\"default-src\"]\n```\n\n\u003cdetails\u003e\n\u003csummary\u003eOutput\u003c/summary\u003e\n\n```\n8-element Vector{String}:\n \"'unsafe-eval'\"\n \"'unsafe-inline'\"\n \"data:\"\n \"filesystem:\"\n \"about:\"\n \"blob:\"\n \"ws:\"\n \"wss:\"\n```\n\u003c/details\u003e\n\n ```julia\njulia\u003e policy[\"script-src\"]\n```\n\u003cdetails\u003e\n\u003csummary\u003eOutput\u003c/summary\u003e\n\n```\n3-element Vector{String}:\n \"'unsafe-eval'\"\n \"'unsafe-inline'\"\n \"https://www.google-analytics.com\"\n ```\n\u003c/details\u003e\n\n# API Reference\n\n## [Policy](@ref)\n\n### Strict Policy \n```julia\nDEFAULT_POLICY\n```\n _Work in progress._ A default, restrictive policy based on various CSP recommendations. Used when creating a Policy where `default = true`. \n\n**See also:** [OWASP CSP cheatsheet](https://cheatsheetseries.owasp.org/cheatsheets/Content_Security_Policy_Cheat_Sheet.html), [mdn csp docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP), [csp.withgoogle.com](https://csp.withgoogle.com/docs/index.html), [CSP Is Dead, Long Live CSP!](https://storage.googleapis.com/pub-tools-public-publication-data/pdf/45542.pdf) and [strict-csp](https://web.dev/strict-csp/).\n\n--------------------------------\n\n```julia\nconst DirectiveTypes = Union{String, Set{String}, Vector{String}, Tuple, Bool}\n```\nDefines acceptable values of a directive.\n\n`Empty` and `false` values are not considered when generating a CSP header.\n\n----------------------------------------------------------\n\n```julia\nPolicy(directives::AbstractDict, report_only=false)\n```\n| Parameter | Type     | Description                |\n| :-------- | :------- | :------------------------- |\n| `directives` | `Dict{String, DirectiveTypes}` | Set of directives that configure your policy\n| `report_only` | `Bool` | **Optional**  Whether to define Policy as [report only](Content-Security-Policy-Report-Only). Defaults to `false`|\n\nDefault constructor. Policies are empty by default.\n```julia\njulia\u003e Policy()\n```\n```json\n{\n    \"report-only\": false\n}\n```\n------------------\n```julia\nPolicy(directives::Pair...; default=false, report_only=false, kwargs...)\n```\n| Parameter | Type     | Description                |\n| :-------- | :------- | :------------------------- |\n| `directives` | `Pair{String,DirectiveTypes}` | Individual policies as a Pair.\n| `default` | `Bool` | **Optional**  Whether to add default directives and default values. Defaults to `false`|\n| `report_only` | `Bool` | **Optional**  Whether to define Policy as [report only](Content-Security-Policy-Report-Only). Defaults to `false`|\n| `kwargs` | `Directives` | **Optional** Directives as keyword arguments. Automatically replaces `_` with `-` in known directives.|\n\u003cdetails\u003e\n\u003csummary\u003eExamples\u003c/summary\u003e\n\n```julia\nPolicy(\"script-src\"=\u003e\"https://example.com/\", \"img-src\"=\u003e\"*\", report_only=true)\n```\n```json\n{\n    \"img-src\": \"*\",\n    \"script-src\": \"https://example.com/\",\n    \"report-only\": true\n}\n```\n```julia\npolicy = Policy(\n     # Set default-src\n     default_src = CSP.self, # \"'self'\"\n     # Set report-uri\n     report_uri = \"https://example.com\",\n     # Report endpoint\n     report_to = \"default\",\n     sandbox = \"allow-downloads\",\n     # Turn on https enforcement\n     upgrade_insecure_requests = true)\n```\n```json\n{\n    \"upgrade-insecure-requests\": true,\n    \"default-src\": \"'self'\",\n    \"report-to\": \"default\",\n    \"sandbox\": \"allow-downloads\",\n    \"report-uri\": \"https://example.com\",\n    \"report-only\": false\n}\n```\n\u003c/details\u003e\n\n-------------------------\n```julia\nPolicy(json::String)\n```\n| Parameter | Type     | Description                |\n| :-------- | :------- | :------------------------- |\n| `json` | `String` | Path to json file, or json string |\n\nBuild a Policy from a JSON configuration.\n\nSee also: [Import from JSON](#policy-from-a-json-file)\n\n----------------------------\n\n## [HTTP](@ref)\n\n```julia\nHTTP.Header(policy::Policy)\n```\n| Parameter | Type     | Description                |\n| :-------- | :------- | :------------------------- |\n| `policy` | `Policy` | A `Policy` instance |\n\nBuild CSP Header\n\n\u003cdetails\u003e\n\u003csummary\u003eExample\u003c/summary\u003e\n\n```julia\nHTTP.Header(Policy(default=true))\n```\n```julia\n\"Content-Security-Policy\" =\u003e \"base-uri none; default-src 'self'; frame-ancestors none; object-src none; report-to default; script-src 'strict-dynamic'\"\n```\n\u003c/details\u003e\n\n----------------------------\n\n```julia\nCSP.meta(policy::Policy; except=CSP.META_EXCLUDED)\n```\n| Parameter | Type     | Description                |\n| :-------- | :------- | :------------------------- |\n| `policy` | `Policy` | A `Policy` instance |\n| `except` | `Vector{String}` | **Optional** Set of directives to exclude from meta element. Defaults to CSP.META_EXCLUDED |\n\nBuild `\u003cmeta\u003e` element, ignoring directives in `except`\n\n\u003cdetails\u003e\n\u003csummary\u003eExample\u003c/summary\u003e\n\n```julia\nCSP.meta(Policy(report_to=\"default\", default_src=\"'self'\"))\n```\n```xml\n\u003cmeta http-equiv=\"Content-Security-Policy\" content=\"default-src 'self'\"\u003e\n```\n\u003c/details\u003e\n\n-------------------------------\n\n\n```julia\nCSP.http(policy::Policy)\n```\n| Parameter | Type     | Description                |\n| :-------- | :------- | :------------------------- |\n| `policy` | `Policy` | A `Policy` instance |\n\nObtain CSP headers as Dict\n\n\u003cdetails\u003e\n\u003csummary\u003eExample\u003c/summary\u003e\n\n```julia\npolicy = csp(\"default-src\"=\u003eCSP.self, \"img-src\"=\u003e(CSP.self, CSP.data), \"report-uri\"=\u003e\"/api/reports\")\n\nCSP.http(policy)\n```\n```\nOrderedCollections.OrderedDict{String, Any} with 3 entries:\n  \"img-src\"     =\u003e \"data: 'self'\"\n  \"default-src\" =\u003e \"'self'\"\n  \"report-uri\"  =\u003e \"/api/reports\"\n```\n\u003c/details\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FcharlieIT%2FContentSecurityPolicy.jl","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FcharlieIT%2FContentSecurityPolicy.jl","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FcharlieIT%2FContentSecurityPolicy.jl/lists"}