
程序员征服安全 OWASP 十大 API 系列-失效的对象级授权
如今,网络安全威胁无处不在,持续不断。情况变得如此糟糕,以至于在部署程序后试图跟上他们的步伐几乎是不可能的。但是,在这个DevSecOps、持续交付和比以往任何时候都更多的数据收益的时代,精明的组织正在帮助他们的开发人员提升技能成为具有安全意识的超级巨星,帮助他们在常见漏洞投入生产之前就将其消除。我们已经解决了 网络漏洞,再加上我们自己的 排名前 8 位的基础设施即代码 错误,现在是时候熟悉下一个重大软件安全挑战了。你准备好了吗?
下一系列博客将重点介绍与应用程序编程接口 (API) 有关的一些最严重的安全漏洞。这些都太糟糕了,以至于他们创建了开放 Web 应用程序安全项目 (OWASP) 主要的 API 漏洞列表。鉴于 API 对现代计算基础架构的重要性,您需要不惜一切代价将这些关键问题排除在应用程序和程序之外。
在对损坏的对象级授权漏洞的检查中,可以找到一个很好的例子,说明为什么必须使用代码来加强安全性。当程序员未能明确定义哪些用户能够查看对象和数据,或提供任何形式的验证来查看、更改或提出其他操作或访问对象的请求,从而允许他们通过 API 端点修改和访问对象和数据时,就会发生这种情况。API 端点是一个接触点,通常是 URL,用于 API 本身与其他系统之间的通信。应用程序之间的连接能力提升了世界上一些最受欢迎的软件的地位,但如果多个端点不密封,则有暴露多个端点的风险。
当程序员忘记或继承父类的属性时,也可能发生这种情况,却没有意识到这样做还会遗漏代码中的关键验证过程。通常,对于使用用户输入访问数据源的每个函数,都应包括对象级授权检查。
认为你已经熟悉这些漏洞了,现在能找到、修复和消除访问控制错误吗?玩游戏化挑战赛:
你过得怎么样?如果你想努力提高自己的分数,请继续阅读!
损坏的对象级授权漏洞的例子有哪些?
对象级访问控制漏洞允许攻击者采取不应允许的操作。这可能是应留给管理员的操作,例如访问或查看敏感数据或销毁记录。在高度安全的环境中,这甚至可能意味着阻止任何人查看记录,除非他们获得特别授权。
定义对象级授权时,应牢记所有可能的操作。例如,在 Java Spring API 中,存在潜在问题的端点可能如下所示:
公共布尔值 deleteOrder(长 ID){
订单订单 = orderRepository.getOne (id);
if(订单 == 空){
log.info(“未找到订单”);
返回 false;
}
用户用户 = order.getUser ();
orderRepository.delete(订购);
log.info(“删除用户 {} 的订单”,user.getId ());
返回真值;
API 端点按 ID 删除订单,但不验证此订单是否由当前登录的用户下达。这为攻击者提供了利用此漏洞并删除其他用户的订单的机会。
为了正确实施安全访问限制,代码将更像这样:
公共布尔值 deleteOrder(长 ID){
用户用户 = userService.getUserbyContext ();
布尔值 orderExist = getUserOrders () .stream ()
.anyMatch(订单->(order.getId () == id));
if (orderExist) {
orderRepository.deleteById (id);
log.info(“删除用户 {} 的订单”,user.getId ());
返回真值;
} 其他 {
log.info(“未找到订单”);
返回 false;
消除损坏的对象级授权漏洞
访问控制代码不必过于复杂。就我们的 Java Spring API 环境示例而言,可以通过严格定义谁可以访问对象来修复这个问题。
首先,必须实施验证程序,以确定谁在提出请求:
用户用户 = userService.getUserbyContext ();
接下来,我们必须确保对象 ID 存在且属于发出请求的用户:
布尔值 orderExist = getUserOrders () .stream ()
.anyMatch(订单->(order.getId () == id));
最后,我们继续删除该对象:
orderRepository.deleteById (id);
请记住,您需要确保代码中的授权方法与组织的用户政策和数据访问控制保持一致。为了确保您的代码完全安全,您应该进行检查,以验证具有不同权限级别的用户是否有权访问他们执行任务所需的数据,但不能查看或更改任何本应限于他们的内容。这样做可能会发现意外忽视的丢失的对象控制漏洞。
这些示例的主要启示是,首先定义用户可以对对象执行的所有操作,然后直接向代码添加强大的访问控制。最后,永远不要相信继承的父财产可以完成这项工作或在其他地方委托这种权力。取而代之的是,在代码中为需要保护的每种对象类型明确定义用户权限和操作。
来看看 安全代码勇士 博客页面,详细了解此漏洞以及如何保护您的组织和客户免受其他安全漏洞的破坏。你也可以 试试演示 Secure Code Warrior 培训平台可让您的所有网络安全技能不断磨练并保持最新状态。
Matias Madou, Ph.D. セキュリティ専門家、研究者、CTO兼共同設立者(Secure Code Warrior )。Ghent大学でアプリケーションセキュリティの博士号を取得し、静的解析ソリューションに焦点を当てた。その後、米国Fortify社に入社し、開発者が安全なコードを書くことを支援せずに、コードの問題を検出するだけでは不十分であることに気づきました。開発者を支援し、セキュリティの負担を軽減し、お客様の期待を上回る製品を開発することを志すようになった。Team Awesomeの一員としてデスクワークをしていないときは、RSA Conference、BlackHat、DefConなどのカンファレンスでプレゼンテーションをするのが好きである。

Secure Code Warriorは、ソフトウェア開発ライフサイクル全体を通じてコードを保護し、サイバーセキュリティを最優先とする文化を醸成するお手伝いをします。AppSecマネージャー、開発者、最高情報セキュリティ責任者(CISO)、あるいはセキュリティに関わるあらゆる方々の組織において、不安全なコードに関連するリスクの低減を支援します。
デモを予約するMatias Madou, Ph.D. セキュリティ専門家、研究者、CTO兼共同設立者(Secure Code Warrior )。Ghent大学でアプリケーションセキュリティの博士号を取得し、静的解析ソリューションに焦点を当てた。その後、米国Fortify社に入社し、開発者が安全なコードを書くことを支援せずに、コードの問題を検出するだけでは不十分であることに気づきました。開発者を支援し、セキュリティの負担を軽減し、お客様の期待を上回る製品を開発することを志すようになった。Team Awesomeの一員としてデスクワークをしていないときは、RSA Conference、BlackHat、DefConなどのカンファレンスでプレゼンテーションをするのが好きである。
マティアスは、15年以上のソフトウェアセキュリティの実務経験を持つ研究者・開発者です。フォーティファイ・ソフトウェア社や自身の会社(Sensei Security)などでソリューションを開発してきました。キャリアの中で、Matiasは、商用製品につながる複数のアプリケーションセキュリティ研究プロジェクトを主導し、10件以上の特許を取得しています。また、RSAカンファレンス、Black Hat、DefCon、BSIMM、OWASP AppSec、BruConなどの世界的なカンファレンスで定期的に講演を行っているほか、高度なアプリケーションセキュリティトレーニング(courses )の講師も務めています。
Matiasはゲント大学でコンピュータ工学の博士号を取得し、アプリケーションの内部構造を隠すためのプログラム難読化によるアプリケーションセキュリティを研究しました。


如今,网络安全威胁无处不在,持续不断。情况变得如此糟糕,以至于在部署程序后试图跟上他们的步伐几乎是不可能的。但是,在这个DevSecOps、持续交付和比以往任何时候都更多的数据收益的时代,精明的组织正在帮助他们的开发人员提升技能成为具有安全意识的超级巨星,帮助他们在常见漏洞投入生产之前就将其消除。我们已经解决了 网络漏洞,再加上我们自己的 排名前 8 位的基础设施即代码 错误,现在是时候熟悉下一个重大软件安全挑战了。你准备好了吗?
下一系列博客将重点介绍与应用程序编程接口 (API) 有关的一些最严重的安全漏洞。这些都太糟糕了,以至于他们创建了开放 Web 应用程序安全项目 (OWASP) 主要的 API 漏洞列表。鉴于 API 对现代计算基础架构的重要性,您需要不惜一切代价将这些关键问题排除在应用程序和程序之外。
在对损坏的对象级授权漏洞的检查中,可以找到一个很好的例子,说明为什么必须使用代码来加强安全性。当程序员未能明确定义哪些用户能够查看对象和数据,或提供任何形式的验证来查看、更改或提出其他操作或访问对象的请求,从而允许他们通过 API 端点修改和访问对象和数据时,就会发生这种情况。API 端点是一个接触点,通常是 URL,用于 API 本身与其他系统之间的通信。应用程序之间的连接能力提升了世界上一些最受欢迎的软件的地位,但如果多个端点不密封,则有暴露多个端点的风险。
当程序员忘记或继承父类的属性时,也可能发生这种情况,却没有意识到这样做还会遗漏代码中的关键验证过程。通常,对于使用用户输入访问数据源的每个函数,都应包括对象级授权检查。
认为你已经熟悉这些漏洞了,现在能找到、修复和消除访问控制错误吗?玩游戏化挑战赛:
你过得怎么样?如果你想努力提高自己的分数,请继续阅读!
损坏的对象级授权漏洞的例子有哪些?
对象级访问控制漏洞允许攻击者采取不应允许的操作。这可能是应留给管理员的操作,例如访问或查看敏感数据或销毁记录。在高度安全的环境中,这甚至可能意味着阻止任何人查看记录,除非他们获得特别授权。
定义对象级授权时,应牢记所有可能的操作。例如,在 Java Spring API 中,存在潜在问题的端点可能如下所示:
公共布尔值 deleteOrder(长 ID){
订单订单 = orderRepository.getOne (id);
if(订单 == 空){
log.info(“未找到订单”);
返回 false;
}
用户用户 = order.getUser ();
orderRepository.delete(订购);
log.info(“删除用户 {} 的订单”,user.getId ());
返回真值;
API 端点按 ID 删除订单,但不验证此订单是否由当前登录的用户下达。这为攻击者提供了利用此漏洞并删除其他用户的订单的机会。
为了正确实施安全访问限制,代码将更像这样:
公共布尔值 deleteOrder(长 ID){
用户用户 = userService.getUserbyContext ();
布尔值 orderExist = getUserOrders () .stream ()
.anyMatch(订单->(order.getId () == id));
if (orderExist) {
orderRepository.deleteById (id);
log.info(“删除用户 {} 的订单”,user.getId ());
返回真值;
} 其他 {
log.info(“未找到订单”);
返回 false;
消除损坏的对象级授权漏洞
访问控制代码不必过于复杂。就我们的 Java Spring API 环境示例而言,可以通过严格定义谁可以访问对象来修复这个问题。
首先,必须实施验证程序,以确定谁在提出请求:
用户用户 = userService.getUserbyContext ();
接下来,我们必须确保对象 ID 存在且属于发出请求的用户:
布尔值 orderExist = getUserOrders () .stream ()
.anyMatch(订单->(order.getId () == id));
最后,我们继续删除该对象:
orderRepository.deleteById (id);
请记住,您需要确保代码中的授权方法与组织的用户政策和数据访问控制保持一致。为了确保您的代码完全安全,您应该进行检查,以验证具有不同权限级别的用户是否有权访问他们执行任务所需的数据,但不能查看或更改任何本应限于他们的内容。这样做可能会发现意外忽视的丢失的对象控制漏洞。
这些示例的主要启示是,首先定义用户可以对对象执行的所有操作,然后直接向代码添加强大的访问控制。最后,永远不要相信继承的父财产可以完成这项工作或在其他地方委托这种权力。取而代之的是,在代码中为需要保护的每种对象类型明确定义用户权限和操作。
来看看 安全代码勇士 博客页面,详细了解此漏洞以及如何保护您的组织和客户免受其他安全漏洞的破坏。你也可以 试试演示 Secure Code Warrior 培训平台可让您的所有网络安全技能不断磨练并保持最新状态。

如今,网络安全威胁无处不在,持续不断。情况变得如此糟糕,以至于在部署程序后试图跟上他们的步伐几乎是不可能的。但是,在这个DevSecOps、持续交付和比以往任何时候都更多的数据收益的时代,精明的组织正在帮助他们的开发人员提升技能成为具有安全意识的超级巨星,帮助他们在常见漏洞投入生产之前就将其消除。我们已经解决了 网络漏洞,再加上我们自己的 排名前 8 位的基础设施即代码 错误,现在是时候熟悉下一个重大软件安全挑战了。你准备好了吗?
下一系列博客将重点介绍与应用程序编程接口 (API) 有关的一些最严重的安全漏洞。这些都太糟糕了,以至于他们创建了开放 Web 应用程序安全项目 (OWASP) 主要的 API 漏洞列表。鉴于 API 对现代计算基础架构的重要性,您需要不惜一切代价将这些关键问题排除在应用程序和程序之外。
在对损坏的对象级授权漏洞的检查中,可以找到一个很好的例子,说明为什么必须使用代码来加强安全性。当程序员未能明确定义哪些用户能够查看对象和数据,或提供任何形式的验证来查看、更改或提出其他操作或访问对象的请求,从而允许他们通过 API 端点修改和访问对象和数据时,就会发生这种情况。API 端点是一个接触点,通常是 URL,用于 API 本身与其他系统之间的通信。应用程序之间的连接能力提升了世界上一些最受欢迎的软件的地位,但如果多个端点不密封,则有暴露多个端点的风险。
当程序员忘记或继承父类的属性时,也可能发生这种情况,却没有意识到这样做还会遗漏代码中的关键验证过程。通常,对于使用用户输入访问数据源的每个函数,都应包括对象级授权检查。
认为你已经熟悉这些漏洞了,现在能找到、修复和消除访问控制错误吗?玩游戏化挑战赛:
你过得怎么样?如果你想努力提高自己的分数,请继续阅读!
损坏的对象级授权漏洞的例子有哪些?
对象级访问控制漏洞允许攻击者采取不应允许的操作。这可能是应留给管理员的操作,例如访问或查看敏感数据或销毁记录。在高度安全的环境中,这甚至可能意味着阻止任何人查看记录,除非他们获得特别授权。
定义对象级授权时,应牢记所有可能的操作。例如,在 Java Spring API 中,存在潜在问题的端点可能如下所示:
公共布尔值 deleteOrder(长 ID){
订单订单 = orderRepository.getOne (id);
if(订单 == 空){
log.info(“未找到订单”);
返回 false;
}
用户用户 = order.getUser ();
orderRepository.delete(订购);
log.info(“删除用户 {} 的订单”,user.getId ());
返回真值;
API 端点按 ID 删除订单,但不验证此订单是否由当前登录的用户下达。这为攻击者提供了利用此漏洞并删除其他用户的订单的机会。
为了正确实施安全访问限制,代码将更像这样:
公共布尔值 deleteOrder(长 ID){
用户用户 = userService.getUserbyContext ();
布尔值 orderExist = getUserOrders () .stream ()
.anyMatch(订单->(order.getId () == id));
if (orderExist) {
orderRepository.deleteById (id);
log.info(“删除用户 {} 的订单”,user.getId ());
返回真值;
} 其他 {
log.info(“未找到订单”);
返回 false;
消除损坏的对象级授权漏洞
访问控制代码不必过于复杂。就我们的 Java Spring API 环境示例而言,可以通过严格定义谁可以访问对象来修复这个问题。
首先,必须实施验证程序,以确定谁在提出请求:
用户用户 = userService.getUserbyContext ();
接下来,我们必须确保对象 ID 存在且属于发出请求的用户:
布尔值 orderExist = getUserOrders () .stream ()
.anyMatch(订单->(order.getId () == id));
最后,我们继续删除该对象:
orderRepository.deleteById (id);
请记住,您需要确保代码中的授权方法与组织的用户政策和数据访问控制保持一致。为了确保您的代码完全安全,您应该进行检查,以验证具有不同权限级别的用户是否有权访问他们执行任务所需的数据,但不能查看或更改任何本应限于他们的内容。这样做可能会发现意外忽视的丢失的对象控制漏洞。
这些示例的主要启示是,首先定义用户可以对对象执行的所有操作,然后直接向代码添加强大的访问控制。最后,永远不要相信继承的父财产可以完成这项工作或在其他地方委托这种权力。取而代之的是,在代码中为需要保护的每种对象类型明确定义用户权限和操作。
来看看 安全代码勇士 博客页面,详细了解此漏洞以及如何保护您的组织和客户免受其他安全漏洞的破坏。你也可以 试试演示 Secure Code Warrior 培训平台可让您的所有网络安全技能不断磨练并保持最新状态。

以下のリンクをクリックして、このリソースのPDFをダウンロードしてください。
Secure Code Warriorは、ソフトウェア開発ライフサイクル全体を通じてコードを保護し、サイバーセキュリティを最優先とする文化を醸成するお手伝いをします。AppSecマネージャー、開発者、最高情報セキュリティ責任者(CISO)、あるいはセキュリティに関わるあらゆる方々の組織において、不安全なコードに関連するリスクの低減を支援します。
レポートを確認するデモを予約するMatias Madou, Ph.D. セキュリティ専門家、研究者、CTO兼共同設立者(Secure Code Warrior )。Ghent大学でアプリケーションセキュリティの博士号を取得し、静的解析ソリューションに焦点を当てた。その後、米国Fortify社に入社し、開発者が安全なコードを書くことを支援せずに、コードの問題を検出するだけでは不十分であることに気づきました。開発者を支援し、セキュリティの負担を軽減し、お客様の期待を上回る製品を開発することを志すようになった。Team Awesomeの一員としてデスクワークをしていないときは、RSA Conference、BlackHat、DefConなどのカンファレンスでプレゼンテーションをするのが好きである。
マティアスは、15年以上のソフトウェアセキュリティの実務経験を持つ研究者・開発者です。フォーティファイ・ソフトウェア社や自身の会社(Sensei Security)などでソリューションを開発してきました。キャリアの中で、Matiasは、商用製品につながる複数のアプリケーションセキュリティ研究プロジェクトを主導し、10件以上の特許を取得しています。また、RSAカンファレンス、Black Hat、DefCon、BSIMM、OWASP AppSec、BruConなどの世界的なカンファレンスで定期的に講演を行っているほか、高度なアプリケーションセキュリティトレーニング(courses )の講師も務めています。
Matiasはゲント大学でコンピュータ工学の博士号を取得し、アプリケーションの内部構造を隠すためのプログラム難読化によるアプリケーションセキュリティを研究しました。
如今,网络安全威胁无处不在,持续不断。情况变得如此糟糕,以至于在部署程序后试图跟上他们的步伐几乎是不可能的。但是,在这个DevSecOps、持续交付和比以往任何时候都更多的数据收益的时代,精明的组织正在帮助他们的开发人员提升技能成为具有安全意识的超级巨星,帮助他们在常见漏洞投入生产之前就将其消除。我们已经解决了 网络漏洞,再加上我们自己的 排名前 8 位的基础设施即代码 错误,现在是时候熟悉下一个重大软件安全挑战了。你准备好了吗?
下一系列博客将重点介绍与应用程序编程接口 (API) 有关的一些最严重的安全漏洞。这些都太糟糕了,以至于他们创建了开放 Web 应用程序安全项目 (OWASP) 主要的 API 漏洞列表。鉴于 API 对现代计算基础架构的重要性,您需要不惜一切代价将这些关键问题排除在应用程序和程序之外。
在对损坏的对象级授权漏洞的检查中,可以找到一个很好的例子,说明为什么必须使用代码来加强安全性。当程序员未能明确定义哪些用户能够查看对象和数据,或提供任何形式的验证来查看、更改或提出其他操作或访问对象的请求,从而允许他们通过 API 端点修改和访问对象和数据时,就会发生这种情况。API 端点是一个接触点,通常是 URL,用于 API 本身与其他系统之间的通信。应用程序之间的连接能力提升了世界上一些最受欢迎的软件的地位,但如果多个端点不密封,则有暴露多个端点的风险。
当程序员忘记或继承父类的属性时,也可能发生这种情况,却没有意识到这样做还会遗漏代码中的关键验证过程。通常,对于使用用户输入访问数据源的每个函数,都应包括对象级授权检查。
认为你已经熟悉这些漏洞了,现在能找到、修复和消除访问控制错误吗?玩游戏化挑战赛:
你过得怎么样?如果你想努力提高自己的分数,请继续阅读!
损坏的对象级授权漏洞的例子有哪些?
对象级访问控制漏洞允许攻击者采取不应允许的操作。这可能是应留给管理员的操作,例如访问或查看敏感数据或销毁记录。在高度安全的环境中,这甚至可能意味着阻止任何人查看记录,除非他们获得特别授权。
定义对象级授权时,应牢记所有可能的操作。例如,在 Java Spring API 中,存在潜在问题的端点可能如下所示:
公共布尔值 deleteOrder(长 ID){
订单订单 = orderRepository.getOne (id);
if(订单 == 空){
log.info(“未找到订单”);
返回 false;
}
用户用户 = order.getUser ();
orderRepository.delete(订购);
log.info(“删除用户 {} 的订单”,user.getId ());
返回真值;
API 端点按 ID 删除订单,但不验证此订单是否由当前登录的用户下达。这为攻击者提供了利用此漏洞并删除其他用户的订单的机会。
为了正确实施安全访问限制,代码将更像这样:
公共布尔值 deleteOrder(长 ID){
用户用户 = userService.getUserbyContext ();
布尔值 orderExist = getUserOrders () .stream ()
.anyMatch(订单->(order.getId () == id));
if (orderExist) {
orderRepository.deleteById (id);
log.info(“删除用户 {} 的订单”,user.getId ());
返回真值;
} 其他 {
log.info(“未找到订单”);
返回 false;
消除损坏的对象级授权漏洞
访问控制代码不必过于复杂。就我们的 Java Spring API 环境示例而言,可以通过严格定义谁可以访问对象来修复这个问题。
首先,必须实施验证程序,以确定谁在提出请求:
用户用户 = userService.getUserbyContext ();
接下来,我们必须确保对象 ID 存在且属于发出请求的用户:
布尔值 orderExist = getUserOrders () .stream ()
.anyMatch(订单->(order.getId () == id));
最后,我们继续删除该对象:
orderRepository.deleteById (id);
请记住,您需要确保代码中的授权方法与组织的用户政策和数据访问控制保持一致。为了确保您的代码完全安全,您应该进行检查,以验证具有不同权限级别的用户是否有权访问他们执行任务所需的数据,但不能查看或更改任何本应限于他们的内容。这样做可能会发现意外忽视的丢失的对象控制漏洞。
这些示例的主要启示是,首先定义用户可以对对象执行的所有操作,然后直接向代码添加强大的访问控制。最后,永远不要相信继承的父财产可以完成这项工作或在其他地方委托这种权力。取而代之的是,在代码中为需要保护的每种对象类型明确定义用户权限和操作。
来看看 安全代码勇士 博客页面,详细了解此漏洞以及如何保护您的组织和客户免受其他安全漏洞的破坏。你也可以 试试演示 Secure Code Warrior 培训平台可让您的所有网络安全技能不断磨练并保持最新状态。
目次
Matias Madou, Ph.D. セキュリティ専門家、研究者、CTO兼共同設立者(Secure Code Warrior )。Ghent大学でアプリケーションセキュリティの博士号を取得し、静的解析ソリューションに焦点を当てた。その後、米国Fortify社に入社し、開発者が安全なコードを書くことを支援せずに、コードの問題を検出するだけでは不十分であることに気づきました。開発者を支援し、セキュリティの負担を軽減し、お客様の期待を上回る製品を開発することを志すようになった。Team Awesomeの一員としてデスクワークをしていないときは、RSA Conference、BlackHat、DefConなどのカンファレンスでプレゼンテーションをするのが好きである。

Secure Code Warriorは、ソフトウェア開発ライフサイクル全体を通じてコードを保護し、サイバーセキュリティを最優先とする文化を醸成するお手伝いをします。AppSecマネージャー、開発者、最高情報セキュリティ責任者(CISO)、あるいはセキュリティに関わるあらゆる方々の組織において、不安全なコードに関連するリスクの低減を支援します。
デモを予約するダウンロード入門に役立つリソース
Trust Agent:AI - Secure and scale AI-Drive development
AI is writing code. Who’s governing it? With up to 50% of AI-generated code containing security weaknesses, managing AI risk is critical. Discover how SCW's Trust Agent: AI provides the real-time visibility, proactive governance, and targeted upskilling needed to scale AI-driven development securely.
OpenText アプリケーションセキュリティのパワー + Secure Code Warrior
OpenText Application Security and Secure Code Warrior combine vulnerability detection with AI Software Governance and developer capability. Together, they help organizations reduce risk, strengthen secure coding practices, and confidently adopt AI-driven development.
Secure Code Warrior corporate overview
Secure Code Warrior is an AI Software Governance platform designed to enable organizations to safely adopt AI-driven development by bridging the gap between development velocity and enterprise security. The platform addresses the "Visibility Gap," where security teams often lack insights into shadow AI coding tools and the origins of production code.





.png)