Skip to content

You can use certain methods to let the plugin provide data like other players' inventories and coordinates. #338

Open

Description

@Minecraft0122

Just like #323 , players can use certain methods to make the plugin directly send other players' inventory, coordinates, ender chest, and other data.

[17:21:21] [Folia Async Scheduler Thread #11/INFO]: [Not Secure] <DrakeBlue> <chat=19005d53-0076-3c39-8750-48973623336a:§f[§bDavid 的物品栏§f]§r/§f[§dDavid 的末影箱§f]§r/§b世界:§fworld §eX:§f-19758224 §eY:§f64 §eZ:§f5776717§r/[bal]/§a21§f §bms§r>

[17:21:32] [Folia Async Scheduler Thread #14/INFO]: [Not Secure] <DrakeBlue> <chat=19005d53-0076-3c39-8750-48973623336a:§f[§bFeakSeng 的物品栏§f]§r/§f[§dFeakSeng 的末影箱§f]§r/§b世界:§fworld §eX:§f28735485 §eY:§f69 §eZ:§f-21166248§r/[bal]/§a38§f §bms§r>

[17:21:39] [Folia Async Scheduler Thread #15/INFO]: [Not Secure] <DrakeBlue> <chat=19005d53-0076-3c39-8750-48973623336a:§f[§bTiamT_T 的物品栏§f]§r/§f[§dTiamT_T 的末影箱§f]§r/§b世界:§fworld §eX:§f8164737 §eY:§f64 §eZ:§f10041137§r/[bal]/§a10§f §bms§r>

[17:21:40] [Folia Region Scheduler Thread #0/INFO]: bahalo issued server command: /interactivechat viewinv 973671cabba41e5ea064ab3fdf5650b8fa94cfc1
[17:21:43] [Folia Region Scheduler Thread #9/INFO]: FeakSeng issued server command: /interactivechat viewender 34aa5236533d1ba0adbd67a739cf6ab13858d8ae
[17:21:47] [Folia Region Scheduler Thread #11/INFO]: FeakSeng issued server command: /interactivechat viewender 5706f805f5e82104adf4a73a12d8c27b9cc068a4

But my velocity recorded his original message, his original message is like this

[17:21:21] [InteractiveChatVelocity - Task Executor #2030/INFO] [simpleproxychat]: [生存1区] DrakeBlue » <chat=8030b484-93cb-3e44-a5c9-97b5258ad3b1:[inv]/[ender]/[pos]/[bal]/[ping]>

[17:21:32] [InteractiveChatVelocity - Task Executor #2030/INFO] [simpleproxychat]: [生存1区] DrakeBlue » <chat=8a8187cc-c11d-32b9-bd0a-b6414a05e8a0:[inv]/[ender]/[pos]/[bal]/[ping]>

[17:21:39] [InteractiveChatVelocity - Task Executor #2030/INFO] [simpleproxychat]: [生存1区] DrakeBlue » <chat=2d498f93-fedc-3e19-aa1b-b564ddf09da1:[inv]/[ender]/[pos]/[bal]/[ping]>

This player has been trying to run 'ic list', 'about', 'plugins', 'bukkit:plugins' on the server.

Well, I installed this plugin on both Velocity and the backend server at the same time. My backend server is folia26.1.2

However, I blocked the commands above through the permission groups, except for 'ic list'.

Activity

  1. LOOHP commented on Sep 12, 2026

    @LOOHP
    Owner

    In the past when this happened, usually there is a plugin conflict with another plugin or a configuration error. As under normal circumstances that plugin blocks input of tags.

    Can you show me your IC config on both the proxy and backend?

  2. Minecraft0122 commented on Sep 12, 2026

    @Minecraft0122
    Author

    过去发生这种情况时,通常是插件与其他插件冲突或配置错误。和正常情况下一样,这个插件会阻止标签输入。

    你能给我看看你代理和后端的IC配置吗?

    Okay, this is the configuration.

    If I remember correctly, I just translated it through AI and didn't really change anything.

    bungeeconfig.yml
    config.yml

  3. Minecraft0122 commented on Oct 6, 2026

    @Minecraft0122
    Author

    查到具体位置了。问题的核心是:InteractiveChat 用消息正文中的 <chat=UUID:…> 标签确定“发言者”,但保护它的输入过滤依赖事件顺序;代理端确实存在会破坏这个过滤链路的代码缺陷。 不能只归因于配置或其他聊天插件冲突。

    我检查的是当前 master 的提交 55528e1bacf497426fd299d358805d578ae78350,并对照了作者为 #323 发布的 2026 年 4 月 17 日改动。以下区分已确认的源码缺陷和仍需复现的部分。

    1. 最根本的位置:后端相信正文里的 UUID

    在 ProcessAccurateSender.java 中,process() 和 find() 用正则匹配 <chat=UUID:…:>,然后直接执行:

    UUID.fromString(matcher.group(1))

    这段代码只负责解析标签,没有验证标签是否由 IC 生成,也没有验证该 UUID 是否属于真实发言者。源码,第 35–74 行

    随后,OutMessagePacket.java 在没有已确定发言者时,用标签中的 UUID 获取 ICPlayer,赋给 sender,再把这个 sender 交给背包、末影箱和自定义占位符模块。身份选择,第 156–185 行、数据解析,第 242–249 行

    因此,只要伪造标签能进入这条处理路径,插件就可能把受害者当作分享数据的人。

    权限检查也不能补救身份错误:背包模块检查的是已经选出的 player.getUniqueId() 是否有分享背包权限,然后读取该玩家的背包。它检查的是被冒充玩家的权限,不是实际输入者是否有权读取对方数据。背包模块,第 77–85 行

    2. 当前仍存在的明确错误:收尾监听器实际上最先执行

    InteractiveChatVelocity.java 的两个收尾方法:

    @Subscribe(priority = Short.MAX_VALUE)
    public void onVelocityChatLast(...)
    

    @Subscribe(priority = Short.MAX_VALUE)
    public void onCommandExecuteLast(...)

    但 Velocity 的规则是:优先级数值越大,越早执行。Short.MAX_VALUE 会让它们在默认优先级为 0 的过滤处理之前运行。IC 监听器代码、Velocity 官方规则

    这直接破坏了预期流程:

    预期顺序 当前默认配置下的顺序
    保存原始消息并过滤标签 收尾方法先运行,此时没有保存的消息
    收尾读取过滤后的结果 过滤方法随后才保存和修改消息
    将签名聊天的修改同步到后端 收尾方法已经运行完,错过同步

    同步发生在 completeHandleChat() 中,它调用 forwardSignedChatEventChange()。同步代码,第 848–859 行

    与此同时,后端 ChatEvents.checkChat() 和 checkCommand() 只在 bungeecordMode == false 时删除输入标签。代理模式开启时,它依赖代理完成过滤。后端过滤条件,第 183–198 行

    这构成了一条明确的风险链:代理过滤结果未正确同步,后端又跳过过滤,最后正文标签被当成身份依据。是否在具体客户端和聊天插件组合中完成绕过,还需要运行复现。

    3. 与 #323 频道命令更直接相关:转发命令可能被误当成“禁止执行”

    代理的 handleCommandExecute() 把:

    event.getResult().isAllowed()

    传给 handleChat(),而后者首先执行:

    if (!isAllowed) {
        return;
    }

    问题在于,Velocity 的 forwardToServer() 返回的是 isAllowed() == false、isForwardToServer() == true。这表示“转交后端执行”,并不表示整个命令被禁止。IC 入口及提前返回、Velocity 命令结果定义

    如果其他监听器先把频道命令设为转发后端,IC 就会直接跳过标签过滤。 这与 #323 中“普通聊天能拦截,但频道发送命令可绕过”的现象相符。不过,尚未取得报告者实际使用的 ChatControl/VelocityControl 版本来确认其事件顺序,因此这是源码确认的条件性绕过路径,不能说已经完整复现了该报告。

    4. 旧版本还有一个已经修改的缺陷

    4 月 17 日之前的 handleChat() 虽然生成了过滤后的 newMessage,但变量 message 仍然保存原始输入。后续聊天分支又使用 message 添加身份标签,并覆盖回 newMessage,导致过滤结果丢失。

    作者的提交 cce1dbb… 已改为从过滤后的消息继续处理,修掉了这处错误;但同一次提交引入了上面提到的 Short.MAX_VALUE 收尾顺序错误。作者当时的修改

    所以,修复应优先处理 Velocity 收尾顺序、转发命令的过滤条件,以及后端标签身份的可信来源。单纯调整 ChatEventPriority 或把频道命令加入解析列表,不能作为完整修复。

    本次是源码诊断,没有修改插件,也没有搭建服务器复现。可以确认上述代码错误存在;#323 的具体插件组合是否正好通过其中哪条路径绕过,仍需用报告者版本做针对性验证。

    查到具体位置了。**问题的核心是:InteractiveChat 用消息正文中的 `` 标签确定“发言者”,但保护它的输入过滤依赖事件顺序;代理端确实存在会破坏这个过滤链路的代码缺陷。** 不能只归因于配置或其他聊天插件冲突。

    我检查的是当前 master 的提交 55528e1bacf497426fd299d358805d578ae78350,并对照了作者为 #323 发布的 2026 年 4 月 17 日改动。以下区分已确认的源码缺陷和仍需复现的部分。

    1. 最根本的位置:后端相信正文里的 UUID

    在 ProcessAccurateSender.java 中,process() 和 find() 用正则匹配 <chat=UUID:…:>,然后直接执行:

    UUID.fromString(matcher.group(1))

    这段代码只负责解析标签,没有验证标签是否由 IC 生成,也没有验证该 UUID 是否属于真实发言者。[源码,第 35–74 行](

    public static final Pattern PATTERN_0 = Pattern.compile("(?:<chat=([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}):(.*?):>)");
    public static final Pattern PATTERN_1 = Pattern.compile("(?:<chat=([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})>)");
    public static final Pattern COLOR_IGNORE_PATTERN = Pattern.compile("(?:(?:§.)*<(?:§.)*c(?:§.)*h(?:§.)*a(?:§.)*t(?:§.)*=((?:(?:§.)*[0-9a-f]){8}(?:§.)*-(?:(?:§.)*[0-9a-f]){4}(?:§.)*-(?:(?:§.)*[0-9a-f]){4}(?:§.)*-(?:(?:§.)*[0-9a-f]){4}(?:§.)*-(?:(?:§.)*[0-9a-f]){12})(?:§.)*>)");
    public static ProcessSenderResult process(Component component) {
    String text = InteractiveChatComponentSerializer.plainText().serialize(component);
    UUID uuid = find(text);
    Matcher matcher0 = PATTERN_0.matcher(text);
    if (matcher0.find()) {
    uuid = UUID.fromString(matcher0.group(1));
    }
    component = ComponentReplacing.replace(component, PATTERN_0.pattern(), false, (result, matchedComponents) -> {
    Component replacement = result.componentGroup(2);
    if (replacement == null) {
    return Component.empty();
    } else {
    return ComponentReplacing.replace(replacement, Registry.ID_UNESCAPE_PATTERN.pattern(), Component.text(">"));
    }
    });
    if (uuid == null) {
    Matcher matcher1 = PATTERN_1.matcher(text);
    if (matcher1.find()) {
    uuid = UUID.fromString(matcher1.group(1));
    }
    }
    component = ComponentReplacing.replace(component, PATTERN_1.pattern(), Component.empty());
    return new ProcessSenderResult(component, uuid);
    }
    public static UUID find(String text) {
    Matcher matcher = PATTERN_0.matcher(text);
    if (matcher.find()) {
    return UUID.fromString(matcher.group(1));
    }
    matcher = PATTERN_1.matcher(text);
    if (matcher.find()) {
    return UUID.fromString(matcher.group(1));
    }
    return null;
    )

    随后,OutMessagePacket.java 在没有已确定发言者时,用标签中的 UUID 获取 ICPlayer,赋给 sender,再把这个 sender 交给背包、末影箱和自定义占位符模块。[身份选择,第 156–185 行](https://github.com/LOOHP/InteractiveChat/blob/55528e1bacf497426fd299d358805d578ae78350/common/src/main/java/com/loohp/interactivechat/listeners/packet/listeners/OutMessagePacket.java#L156-L185)、[[数据解析,第 242–249 行](https://github.com/LOOHP/InteractiveChat/blob/55528e1bacf497426fd299d358805d578ae78350/common/src/main/java/com/loohp/interactivechat/listeners/packet/listeners/OutMessagePacket.java#L242-L249)](https://github.com/LOOHP/InteractiveChat/blob/55528e1bacf497426fd299d358805d578ae78350/common/src/main/java/com/loohp/interactivechat/listeners/packet/listeners/OutMessagePacket.java#L242-L249)

    因此,只要伪造标签能进入这条处理路径,插件就可能把受害者当作分享数据的人。

    权限检查也不能补救身份错误:背包模块检查的是已经选出的 player.getUniqueId() 是否有分享背包权限,然后读取该玩家的背包。它检查的是被冒充玩家的权限,不是实际输入者是否有权读取对方数据。[背包模块,第 77–85 行](

    if (optplayer.isPresent()) {
    ICPlayer player = optplayer.get();
    if (PlayerUtils.hasPermission(player.getUniqueId(), "interactivechat.module.inventory", true, 5)) {
    Component replaceText = InteractiveChat.invReplaceText;
    String title = ChatColorUtils.translateAlternateColorCodes('&', PlaceholderParser.parse(player, InteractiveChat.invTitle));
    String sha1 = HashUtils.createSha1(player.isRightHanded(), player.getSelectedSlot(), player.getExperienceLevel(), title, player.getInventory());
    if (!preview && !InteractiveChat.inventoryDisplay.containsKey(sha1)) {
    layout0(player, sha1, title, receiver, component, unix);
    )

    2. 当前仍存在的明确错误:收尾监听器实际上最先执行

    InteractiveChatVelocity.java 的两个收尾方法:

    @Subscribe(priority = Short.MAX_VALUE)
    public void onVelocityChatLast(...)
    
    @Subscribe(priority = Short.MAX_VALUE)
    public void onCommandExecuteLast(...)

    但 Velocity 的规则是:优先级数值越大,越早执行。Short.MAX_VALUE 会让它们在默认优先级为 0 的过滤处理之前运行。[IC 监听器代码](https://github.com/LOOHP/InteractiveChat/blob/55528e1bacf497426fd299d358805d578ae78350/common/src/main/java/com/loohp/interactivechat/proxy/velocity/InteractiveChatVelocity.java#L653-L730)、[[Velocity 官方规则](https://github.com/PaperMC/Velocity/blob/dev/3.0.0/api/src/main/java/com/velocitypowered/api/event/Subscribe.java)](https://github.com/PaperMC/Velocity/blob/dev/3.0.0/api/src/main/java/com/velocitypowered/api/event/Subscribe.java)

    这直接破坏了预期流程:

    预期顺序 当前默认配置下的顺序
    保存原始消息并过滤标签 收尾方法先运行,此时没有保存的消息
    收尾读取过滤后的结果 过滤方法随后才保存和修改消息
    将签名聊天的修改同步到后端 收尾方法已经运行完,错过同步

    同步发生在 completeHandleChat() 中,它调用 forwardSignedChatEventChange()。[同步代码,第 848–859 行](

    private void completeHandleChat(Player player, String eventMessage, String newMessage, Consumer<String> setResult) {
    if (!eventMessage.equals(newMessage)) {
    if (isUsingSignedChatPackets(player)) {
    try {
    PluginMessageSendingVelocity.forwardSignedChatEventChange(player.getUniqueId(), eventMessage, newMessage, System.currentTimeMillis());
    } catch (IOException e) {
    e.printStackTrace();
    }
    } else {
    setResult.accept(newMessage);
    }
    }
    )

    与此同时,后端 ChatEvents.checkChat() 和 checkCommand() 只在 bungeecordMode == false 时删除输入标签。代理模式开启时,它依赖代理完成过滤。[后端过滤条件,第 183–198 行](

    public static void checkChat(AsyncPlayerChatEvent event) {
    if (!InteractiveChat.bungeecordMode) {
    event.setMessage(Registry.ID_PATTERN.matcher(event.getMessage()).replaceAll(""));
    }
    translateAltColorCode(event);
    String processedMessage = checkMention(event);
    event.setMessage(processedMessage);
    checkChatMessage(event);
    }
    public static void checkCommand(PlayerCommandPreprocessEvent event) {
    if (!InteractiveChat.bungeecordMode) {
    event.setMessage(Registry.ID_PATTERN.matcher(event.getMessage()).replaceAll(""));
    }
    )

    这构成了一条明确的风险链:代理过滤结果未正确同步,后端又跳过过滤,最后正文标签被当成身份依据。是否在具体客户端和聊天插件组合中完成绕过,还需要运行复现。

    3. 与 #323 频道命令更直接相关:转发命令可能被误当成“禁止执行”

    代理的 handleCommandExecute() 把:

    event.getResult().isAllowed()

    传给 handleChat(),而后者首先执行:

    if (!isAllowed) {
        return;
    }

    问题在于,Velocity 的 forwardToServer() 返回的是 isAllowed() == false、isForwardToServer() == true。这表示“转交后端执行”,并不表示整个命令被禁止。[IC 入口及提前返回](https://github.com/LOOHP/InteractiveChat/blob/55528e1bacf497426fd299d358805d578ae78350/common/src/main/java/com/loohp/interactivechat/proxy/velocity/InteractiveChatVelocity.java#L713-L744)、[[Velocity 命令结果定义](https://github.com/PaperMC/Velocity/blob/dev/3.0.0/api/src/main/java/com/velocitypowered/api/event/command/CommandExecuteEvent.java#L230-L248)](https://github.com/PaperMC/Velocity/blob/dev/3.0.0/api/src/main/java/com/velocitypowered/api/event/command/CommandExecuteEvent.java#L230-L248)

    如果其他监听器先把频道命令设为转发后端,IC 就会直接跳过标签过滤。 这与 #323 中“普通聊天能拦截,但频道发送命令可绕过”的现象相符。不过,尚未取得报告者实际使用的 ChatControl/VelocityControl 版本来确认其事件顺序,因此这是源码确认的条件性绕过路径,不能说已经完整复现了该报告。

    4. 旧版本还有一个已经修改的缺陷

    4 月 17 日之前的 handleChat() 虽然生成了过滤后的 newMessage,但变量 message 仍然保存原始输入。后续聊天分支又使用 message 添加身份标签,并覆盖回 newMessage,导致过滤结果丢失。

    作者的提交 cce1dbb… 已改为从过滤后的消息继续处理,修掉了这处错误;但同一次提交引入了上面提到的 Short.MAX_VALUE 收尾顺序错误。[作者当时的修改](cce1dbb)

    所以,修复应优先处理 Velocity 收尾顺序、转发命令的过滤条件,以及后端标签身份的可信来源。单纯调整 ChatEventPriority 或把频道命令加入解析列表,不能作为完整修复。

    本次是源码诊断,没有修改插件,也没有搭建服务器复现。可以确认上述代码错误存在;#323 的具体插件组合是否正好通过其中哪条路径绕过,仍需用报告者版本做针对性验证。

  4. Minecraft0122 commented on Oct 6, 2026

    @Minecraft0122
    Author

    I use GPT to find this question. Answer like above

  5. LOOHP commented on Oct 6, 2026

    @LOOHP
    Owner

    Looking at your backend IC config, it seems like you haven't enabled Bungeecord: false. Have you tried that first?

  6. Minecraft0122 commented on Oct 6, 2026

    @Minecraft0122
    Author

    It seems like it didn't start, I'll give it a try.

  7. Minecraft0122 commented on Oct 6, 2026

    @Minecraft0122
    Author

    I tried it, and even when it starts, the problem still exists.

  8. LOOHP commented on Oct 6, 2026

    @LOOHP
    Owner

    What exactly did you type into the chat to trigger the issue?

  9. Minecraft0122 commented on Oct 6, 2026

    @Minecraft0122
    Author

    <chat=8030b484-93cb-3e44-a5c9-97b5258ad3b1:[inv]/[ender]/[pos]/[bal]/[ping]>

  10. LOOHP commented on Oct 6, 2026

    @LOOHP
    Owner

    Can you try whether the issue occurs if you type these two?

    <chat=8030b484-93cb-3e44-a5c9-97b5258ad3b1:[inv]:>
    
    <chat=8030b484-93cb-3e44-a5c9-97b5258ad3b1:[inv]/[ender]/[pos]/[bal]/[ping]:>
    

    Notice the extra : near the end.

  11. Minecraft0122 commented on Oct 11, 2026

    @Minecraft0122
    Author

    There will be.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions