fix SSRF: validate user_id before GitHub API URL in starred()#1144
fix SSRF: validate user_id before GitHub API URL in starred()#1144
Conversation
- admin/problem_df_change.php: wrap hlist processing in braces and apply array_map intval - admin/contest_add.php: same fix for hlist bypass of intval protection
- Add is_valid_user_name() check before embedding user_id in URL - Apply preg_replace whitelist filter (a-z 0-9 - _) as second layer - Prevents injection of internal addresses or arbitrary URLs if starred() is ever called with unchecked user input
There was a problem hiding this comment.
Pull request overview
This PR tightens input handling around user-controlled identifiers to reduce the risk of unsafe URL construction in starred() and to harden admin-side comma-separated ID lists used in SQL IN (...) clauses.
Changes:
- Add
user_idvalidation/sanitization before building the GitHub API URL instarred(). - Sanitize
hlistID lists in admin endpoints by coercing elements to integers before building SQL. - Minor formatting/structure updates around
hlistparsing.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| trunk/web/include/my_func.inc.php | Adds user_id validation before constructing the GitHub API request URL in starred(). |
| trunk/web/admin/problem_df_change.php | Sanitizes posted hlist values by converting list elements to integers before SQL IN (...). |
| trunk/web/admin/contest_add.php | Applies similar integer coercion for hlist parsing in the problem2contest flow. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if (!$user_id || !is_valid_user_name($user_id)) { | ||
| return false; | ||
| } | ||
| $safe_user_id = preg_replace('/[^a-zA-Z0-9\-_]/', '', $user_id); |
There was a problem hiding this comment.
The second whitelist check conflicts with is_valid_user_name(): is_valid_user_name() allows a leading '' (see its implementation), but preg_replace() strips it and then the strict equality check forces a false return. If leading '' is valid in this codebase, adjust the whitelist to allow it (or use a single consistent validator). If this is meant to validate GitHub usernames specifically, consider replacing both checks with a dedicated GitHub-username validation and/or rawurlencode() the path segment instead of mutating then comparing.
| $safe_user_id = preg_replace('/[^a-zA-Z0-9\-_]/', '', $user_id); | |
| $safe_user_id = preg_replace('/[^a-zA-Z0-9\-\*_]/', '', $user_id); |
| $pieces = explode(",",$plist); | ||
| $pieces = array_unique($pieces); | ||
| if($pieces[0]=="")unset($pieces[0]); | ||
| // 安全修复:每个ID元素强制intval,防止SQL注入 | ||
| $plist = implode(",", array_map('intval', $pieces)); |
There was a problem hiding this comment.
array_map('intval', $pieces) will coerce empty/non-numeric entries to 0, which can produce unintended IDs in the IN() list (e.g. input "1,,2" becomes "1,0,2"). Consider trimming each element, filtering out empty/non-numeric values, and dropping <=0 IDs before implode() so the SQL only targets intended problem_ids.
| $pieces = explode(",",$plist); | |
| $pieces = array_unique($pieces); | |
| if($pieces[0]=="")unset($pieces[0]); | |
| // 安全修复:每个ID元素强制intval,防止SQL注入 | |
| $plist = implode(",", array_map('intval', $pieces)); | |
| $pieces = explode(",", $plist); | |
| // 去除每个元素两端空白 | |
| $pieces = array_map('trim', $pieces); | |
| // 过滤掉空字符串、非纯数字或非正数的ID,避免产生0或非法ID | |
| $pieces = array_filter($pieces, function ($v) { | |
| return $v !== '' && ctype_digit($v) && intval($v) > 0; | |
| }); | |
| // 去重 | |
| $pieces = array_unique($pieces); | |
| if (empty($pieces)) { | |
| $plist = ""; | |
| } else { | |
| // 现在$pieces中仅包含经过验证的正整数ID字符串 | |
| $plist = implode(",", $pieces); | |
| } |
trunk/web/admin/contest_add.php
Outdated
| $plist = trim($_POST['hlist']); | ||
| $pieces = explode(",",$plist ); | ||
| $pieces = explode(",",$plist); | ||
| $pieces = array_unique($pieces); | ||
| if($pieces[0]=="") unset($pieces[0]); | ||
| $plist=implode(",",$pieces); | ||
| // 安全修复:每个ID元素强制intval,防止SQL注入 | ||
| $plist = implode(",", array_map('intval', $pieces)); |
There was a problem hiding this comment.
This branch reads $_POST['hlist'] unconditionally; if the form submits problem2contest without hlist, it will raise an undefined index notice and $plist parsing will behave unexpectedly. Please guard access with isset()/?? and apply the same trim/filter-before-intval approach so empty/non-numeric items don’t become 0 in the generated list.
Fix SSRF in starred() function
问题
include/my_func.inc.php的starred()函数将$user_id直接拼入 GitHub API URL,若将来调用方式变化导致外部输入进入,可构造内网地址(如127.0.0.1:1536)进行 SSRF 探测。修复
在拼入 URL 前加两层校验:
is_valid_user_name()通用格式校验preg_replace('/[^a-zA-Z0-9\-_]/', '', ...)白名单过滤