Browse Source

fix: resolve security vulnerabilities from code scanning (#11641)

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
pull/11644/head
afc163 6 months ago
committed by GitHub
parent
commit
aa4c47ee48
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 4
      .github/workflows/deploy.yml
  2. 3
      .github/workflows/emoji-helper.yml
  3. 3
      .github/workflows/issue-labeled.yml
  4. 3
      .github/workflows/issue-open-check.yml
  5. 18
      .github/workflows/preview-deploy.yml
  6. 3
      .gitignore
  7. 5
      mock/listTableList.ts
  8. 24
      src/pages/user/login/index.tsx
  9. 6
      src/service-worker.js

4
.github/workflows/deploy.yml

@ -5,6 +5,10 @@ on:
branches:
- all-blocks
permissions:
contents: write
pages: write
jobs:
build-and-deploy:
runs-on: ubuntu-latest

3
.github/workflows/emoji-helper.yml

@ -4,6 +4,9 @@ on:
release:
types: [published]
permissions:
contents: write
jobs:
emoji:
runs-on: ubuntu-latest

3
.github/workflows/issue-labeled.yml

@ -4,6 +4,9 @@ on:
issues:
types: [labeled]
permissions:
issues: write
jobs:
reply-helper:
runs-on: ubuntu-latest

3
.github/workflows/issue-open-check.yml

@ -4,6 +4,9 @@ on:
issues:
types: [opened, edited]
permissions:
issues: write
jobs:
check-issue:
runs-on: ubuntu-latest

18
.github/workflows/preview-deploy.yml

@ -26,7 +26,14 @@ jobs:
- name: save PR id
id: pr
run: echo "::set-output name=id::$(<pr-id.txt)"
run: |
PR_ID=$(<pr-id.txt)
# Validate PR ID is numeric to prevent code injection
if [[ ! "$PR_ID" =~ ^[0-9]+$ ]]; then
echo "Invalid PR ID: $PR_ID"
exit 1
fi
echo "id=$PR_ID" >> "$GITHUB_OUTPUT"
- name: download dist artifact
uses: dawidd6/action-download-artifact@v6
@ -84,7 +91,14 @@ jobs:
- name: save PR id
id: pr
run: echo "::set-output name=id::$(<pr-id.txt)"
run: |
PR_ID=$(<pr-id.txt)
# Validate PR ID is numeric to prevent code injection
if [[ ! "$PR_ID" =~ ^[0-9]+$ ]]; then
echo "Invalid PR ID: $PR_ID"
exit 1
fi
echo "id=$PR_ID" >> "$GITHUB_OUTPUT"
- name: The job failed
uses: actions-cool/maintain-one-comment@v1.2.1

3
.gitignore

@ -42,3 +42,6 @@ screenshot
.firebase
build
# worktrees
.worktrees

5
mock/listTableList.ts

@ -106,11 +106,6 @@ function getRule(req: Request, res: Response, u: string) {
}
function postRule(req: Request, res: Response, u: string, b: Request) {
let realUrl = u;
if (!realUrl || Object.prototype.toString.call(realUrl) !== '[object String]') {
realUrl = req.url;
}
const body = b?.body || req.body;
const { method, name, desc, key } = body;

24
src/pages/user/login/index.tsx

@ -118,6 +118,27 @@ const Login: React.FC = () => {
const { message } = App.useApp();
const intl = useIntl();
/**
* Validate redirect URL to prevent open redirect attacks
* Only allow same-origin relative paths starting with '/'
*/
const getSafeRedirectUrl = (redirect: string | null): string => {
if (!redirect || !redirect.startsWith('/')) return '/';
// Block protocol-relative URLs (//example.com)
if (redirect.startsWith('//')) return '/';
try {
const parsed = new URL(redirect, window.location.origin);
// Only allow same-origin URLs
if (parsed.origin !== window.location.origin) return '/';
// Return the path with query and hash preserved
return `${parsed.pathname}${parsed.search}${parsed.hash}`;
} catch {
return '/';
}
};
const fetchUserInfo = async () => {
const userInfo = await initialState?.fetchUserInfo?.();
if (userInfo) {
@ -142,7 +163,8 @@ const Login: React.FC = () => {
message.success(defaultLoginSuccessMessage);
await fetchUserInfo();
const urlParams = new URL(window.location.href).searchParams;
window.location.href = urlParams.get('redirect') || '/';
const redirectUrl = getSafeRedirectUrl(urlParams.get('redirect'));
window.location.href = redirectUrl;
return;
}
console.log(msg);

6
src/service-worker.js

@ -45,6 +45,12 @@ workbox.routing.registerRoute(
/** Response to client after skipping waiting with MessageChannel */
addEventListener('message', (event) => {
// Security: Verify origin to prevent cross-origin attacks
// Use self.location.origin for dynamic origin validation (works across all deployment domains)
if (event.origin !== self.location.origin) {
return;
}
const replyPort = event.ports[0];
const message = event.data;
if (replyPort && message && message.type === 'skip-waiting') {

Loading…
Cancel
Save