We use something like this:
String taskId = ...;
ProcessEngineServices processEngineServices = ...;
Task task = processEngineServices.getTaskService().createTaskQuery().taskId(taskId).singleResult();
String taskDefinitionKey = task.getTaskDefinitionKey();
String processDefinitionId = task.getProcessDefinitionId();
Optional<String> myPropertyValue = processEngineServices
.getRepositoryService()
.getBpmnModelInstance(processDefinitionId)
.getModelElementsByType(UserTask.class)
.stream()
.filter(userTask -> userTask.getId().equals(taskDefinitionKey))
.map(UserTask::getExtensionElements)
.filter(Objects::nonNull)
.flatMap(e -> e.getElementsQuery().filterByType(CamundaProperties.class).list().stream())
.flatMap(e -> e.getCamundaProperties().stream())
.filter(e -> e.getCamundaName().equals("myProperty"))
.map(CamundaProperty::getCamundaValue)
.findAny();