Hacktoberfest 2026:メンテナが10月に向けて印を付けた、オープンで初心者向けの issue。 Hacktoberfest の issue を見る

Optional integrations build inline <script> elements, forcing script-src 'unsafe-inline'

オープン
#6,078 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る

メンテナーはふだん 3 日以内に返信

まだ誰も着手していません。

評価

難易度
4/5
見積もり時間
3〜5日
初心者へのやさしさ
48/100
issue の種類
機能追加
明瞭さ
明確に書かれている
活発さ
静か
技術スタック
angular, typescript
領域
frontend, security

調査の方向性

Start with the listed script creation sites in src/app/statistics/google-analytics.service.ts, src/app/core/shared/client-math.service.ts, src/app/core/google-recaptcha/google-recaptcha.service.ts, src/app/social/social.service.ts, and src/app/statistics/matomo.factory.ts; check how #6077 exposes CSP_NONCE. Remove inline script assignments and apply the configured nonce to dynamic scripts, then verify the acceptance criteria across all five integrations, including behavior without a nonce.

索引モデルが issue の本文から書いたものです。

説明

needs discussion new feature security

Is your feature request related to a problem? Please describe.

Two of the optional integrations construct <script> elements with inline content at runtime.
Any deployment that enables them therefore requires script-src 'unsafe-inline', which is the
single directive value that most undermines a Content-Security-Policy.

Google Analytics (src/app/statistics/google-analytics.service.ts:71-85) builds the config
snippet as inline script for both the GTag and the legacy variant:

const libScript = this.document.createElement('script');
libScript.innerHTML = `window.dataLayer = window.dataLayer || [];function gtag(){window.dataLayer.push(arguments);}
                     gtag('js', new Date());gtag('config', '${trackingId}');`;
this.document.body.appendChild(libScript);

MathJax (src/app/core/shared/client-math.service.ts:83-86) does the same for its options
object:

const optionsScript: HTMLScriptElement = this._document.createElement('script');
optionsScript.type = 'text/javascript';
optionsScript.text = `MathJax = ${JSON.stringify(this.mathJaxOptions)};`;
this._document.head.appendChild(optionsScript);

In both cases the inline script does nothing that could not be done directly in TypeScript. It
assigns a global. Routing it through a <script> element buys nothing and costs the ability to
run under a meaningful CSP.

Separately, several services inject external scripts at runtime, which is fine in itself but
becomes relevant under a nonce-based policy that does not use 'strict-dynamic', since a
dynamically created script element carries no nonce:

Service Location
Google Analytics / GTag src/app/statistics/google-analytics.service.ts:67
Google reCAPTCHA src/app/core/google-recaptcha/google-recaptcha.service.ts:182
MathJax src/app/core/shared/client-math.service.ts:88
AddToAny social sharing src/app/social/social.service.ts:82
Matomo src/app/statistics/matomo.factory.ts:19-24

Describe the solution you'd like

1. Remove the two inline script blocks. Assign the globals directly instead of via a script
element:

// MathJax: set the global before loading the library, no script element needed
(window as any).MathJax = this.mathJaxOptions;

// Google Analytics: same, define dataLayer and gtag in TypeScript

This alone removes the need for script-src 'unsafe-inline' on deployments that enable Analytics
or MathJax, and is worth doing independently of any nonce work.

2. Apply the nonce to dynamically created script elements. Once #6077 provides CSP_NONCE,
each of the services above should set script.nonce = inject(CSP_NONCE) on the element it creates.
This is a no-op when no nonce is configured, so it is backwards compatible, and it makes the
integrations work under an explicit-allowlist policy rather than depending on 'strict-dynamic'.

A small shared helper (for example createScriptElement(doc, src, nonce)) would avoid repeating
this in five places and would make it harder for a future integration to reintroduce the problem.

Acceptance criteria

  • No innerHTML or .text assignment on a <script> element remains in src/.
  • Every dynamically created <script> element carries the nonce when one is configured,
    verifiable in the DOM with Analytics, Matomo, MathJax, reCAPTCHA and AddToAny all enabled.
  • With those five enabled and a policy of script-src 'nonce-X' 'strict-dynamic' (no
    'unsafe-inline', no 'unsafe-eval'), all five load and function with zero CSP violations.
  • Existing behaviour is unchanged when no nonce is configured.

Describe alternatives or workarounds you've considered

  • Rely on 'strict-dynamic'. Because these scripts are created via createElement rather than
    by the HTML parser, 'strict-dynamic' would permit them as-is, including the inline ones. That
    is the pragmatic first step proposed in #6077, but it means trusting anything application code
    loads, so it should not be the permanent answer.
  • Allowlist the hosts in the policy. Works for the external scripts but not the inline ones, and
    several of the hosts are runtime configuration rather than build-time constants (see phase 3 in
    #6079).

Additional information

Umbrella: #6079. Depends on #6077 only for part 2; part 1 is independent and can be merged
first.

主要言語
TypeScript
スター
180
フォーク
577
平均マージ
2日 12時間
マージ済み PR(30日)
111

環境構築

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

DSpace/dspace-angular のほかの issue

DSpace/dspace-angular の issue をすべて見る

似ている issue

TypeScript の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。